页面呈现流程
- 浏览器会将获取到的HTML代码解析成一个DOM树(包括display: none的元素)
- 在DOM树的基础上根据节点的几何属性(margin/padding/width/height等)生成render树(不包括display: none、head节点但是会包含visibility:hidden节点)
-
在render树的基础上进一步渲染样式
微信图片_20190227175527.png
repaint、reflow概念
回流(reflow):当render树种的元素因为大小,布局,隐藏、增减等原因而引起的重建叫做回流
重绘(repaint):当元素的一部分属性发生变化的时候,会影响外观但是不会引起布局变化(比如background-color)而重新渲染的过程叫重绘
引起回流的原因
- 页面初始化渲染
- DOM节点的增加和删除
- 元素位置发生改变
- 元素几何属性发生变化 - border、width、height、padding、margin
- 浏览器窗口发生变化(resize)
- 获取某些属性 - offsetTop、offsetLeft、offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle() (currentStyle in IE)
var s = document.body.style;
s.padding = "2px"; // 回流 + 重绘
s.border = "1px solid red"; // 再一次 回流+重绘
s.color = "blue"; // 再一次重绘
s.backgroundColor = "#ccc"; // 再一次 重绘
s.fontSize = "14px"; // 再一次 回流+重绘
// 添加node,再一次 回流+重绘
document.body.appendChild(document.createTextNode('abc!'));
上面代码一共引起了4次回流和6次重绘,但是浏览器并不会每一条js语句就执行一次,而是等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush对象,进行批量处理,这样就会让多次回流、重绘变成一次回流重绘。
当我们去获取第六点那些属性的时候,浏览器为了能给你返回一个比较精确的答案,他会提前flush队列,因为队列中可能会有影响这些值的操作,所以获取这些属性也会引起回流
优化
- 使用class将多次改变样式属性的操作合并成一次操作
var changeDiv = document.getElementById('changeDiv');
changeDiv.style.color = '#093';
changeDiv.style.background = '#eee';
changeDiv.style.height = '200px';
// 可以添加一个class
div.changeDiv {
background: #eee;
color: #093;
height: 200px;
}
为这个节点添加这个className
document.getElementById('changeDiv').className = 'changeDiv';
- 让要操作的元素进行"离线处理",处理完后一起更新
a)使用DocumentFragment进行缓存操作,引发一次回流和重绘
b)使用display:none,如果要对一个元素进行复杂操作,可以先隐藏他,操作完成之后在显示,这样只引发两次回流和重绘
c)使用cloneNode(true/false)和replaceChild,引发一次回流和重绘 - 将需要多次重排的元素,position属性设置为absolute或者fixed,这样此元素会脱离文档流,他的变化不会影响到其他元素。例如有动画效果的元素最好设置为绝对定位。
- 在内存中多次操作节点,可以一起操作完成之后再添加到文档中去。
- 在需要经常获取那些引起浏览器回流的属性值是,可以缓存到变量中,而不是每次去重新获取。
参考文档:
网友评论