一、浏览器渲染机制
- 浏览器采用流式布局(Flow Based Layout)
- 浏览器会把HTML解析成DOM, 把CSS解析成CSSOM,DOM和CSSOM合并就产生的渲染树(Render Tree)
- 有了RenderTree, 我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后绘制的页面上
- 由于浏览器使用流式布局,对Render Tree的计算通常只需要遍历一次即可完成。 但table及其内部元素除外,他们可能需要多次计算,通常需要花费3倍于同等元素的时间,这也是为什么要避免使用table布局的原因
二、重绘
由于接到的几何属性发生改变或者由于样式发生改变而不影响布局的,称为重绘。例如outline, visibility, color, background-color等,重绘的代价是高昂的,因为浏览器必须验证DOM树上其他节点元素的可见性。
三、回流
回流是布局或者几何属性需要改变称为回流。回流影响浏览器性能的关键因素,因为其变化涉及到部分页面(或是整个页面)的布局更新。一个元素的回流可能胡导致了其所有子元素以及DOM中紧随其后的节点、祖先节点元素的随后的回流。
* **回流必定会导致重绘, 重绘不一定会引起回流
四、浏览器优化
现代浏览器大多都是通过队列机制来批量更新布局,浏览器会把修改操作放在队列中,至少一个浏览器刷新才会情况队列,但当你获取布局信息的时候,队列中可能会影响这些属性或方法返回值的操作,即使没有,浏览器也会强制清空队列,触发回流和重绘来确保返回正确的值。
主要包括以下属性和方法:
offsetTop、offsetLeft、offsetWidth、 offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientWidth、clientHeight、clientTop、clientLeft、width、height、getComputedStyle()、getBoundingClientRect()
所有我们应该避免频繁使用上述属性,他们都会强制渲染刷新队列
五、减少重绘和回流
1、CSS
- 使用transform替代top
- 使用visibility替换display: none, 因为前者只会引起重绘,后者会引发回流
- 避免是有table布局,可能很小的一个小改动会造成在整个table的重新布局
- 尽可能在DOM树的最末端改变class,回流是不可避免的,但是可以减少其影响。
- 避免设置多层内联样式,CSS选择符从右往左匹配查找,避免节点层级过多
- 将动画效果应用到position属性为absolute或fixed的元素上,避免影响其他元素的布局,这样只是一个重绘,而不是回流,同时,控制动画速度可以选择requestAnimationFrame.
- 避免使用CSS表达式,可能会引发回流
- 将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点,例如will-change、video、iframe等标签,浏览器会自动将该节点设为图层
- CSS硬件加速(GPU加速),使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘。但是对于动画的其他属性,比如background-color这些,还是会引起重绘的,不过它还是可以提升这些动画的性能
2、JavaScript
- 避免频繁操作样式,最好一次性重新style属性,或者将样式列表定义为class并一次性更改class属性。
- 避免评分操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中
- 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个遍历缓存起来
- 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素以及后续元素频繁回流