浏览器重排(回流),重绘,合成

543 阅读4分钟

重排:更新了元素的几何属性之后,重新触发布局,更新完整的渲染流程的过程,关键在于修改了元素的几何属性.
一些会引起重排操作的情况

添加/删除可见的DOM元素
元素的位置发生变化  
元素的尺寸发生变化(外边距、内边框、边框、高度和宽度)  
内容发生变化(文本变化、图片被另一个不同尺寸的图片所替代)  
浏览器的窗口尺寸变化(回流是根据视口的大小来计算元素的位置和大小的)  

根据改变的范围和程度,渲染树中或大或小的部分需要重新计算,有些改变会触发整个页面的重排(例如滚动条出现的时候、修改了根节点)

重绘:没有引起几何位置的变化,浏览器会直接进入图层回值阶段,然后执行之后的渲染流程;关键在于更新的是绘制属性,不会引起几何位置的变化,如修改了元素的背景颜色或者文字颜色,会从图层绘制阶段开始更新渲染流水线,相较于重排操作,重绘省去了布局和分层阶段,执行效率高于重排操作。

重排一定会发生重绘,重绘不一定会发生重排

合成:若修改一个既不要布局也不要绘制的属性,渲染引擎将直接跳过布局和图层绘制的阶段,只执行后续的合成操作,这个过程叫做合成。合成可以大大提升绘制效率。 比如transform来实现动画效果,直接在非主线程上执行合成动画操作,没有直接占用主线程的资源,也避开了布局和绘制两个子阶段。

浏览器的优化:大多数浏览器会通过队列机制来批量更新布局,浏览器会将修改操作放入到队列里,至少一个浏览器刷新才会清空队列,可以让多次的重排,重绘变成一次回流重绘。
缺点:但是在获取布局信息时,队列可能有会影响这些属性或方法返回值的操作,即使没有也会强制清空队列,触发重排与重绘来确保返回正确的值;包括offset...,scroll...,client...,width,height,getComputedStyle(),getBoundingClientRect(),尽量避免使用。

如何减少重排,重绘
作用:省去了布局和绘制阶段,这样少了渲染进程的主线程和非主线程的计算操作,能够加快页面的渲染展示。

在写js代码时

避免频繁操作样式
避免频繁操作DOM
避免频繁读取会引发回流/重绘的属性
对具有复杂动画的元素使用绝对定位,使它脱离文档流

在写css代码时

使用transform替代top
使用visibility替代display:none
避免使用table布局
尽可能在dom树的最末端改变class
避免设置多层内联样式,css选择符从右往左匹配查找,避免节点层级过多
将动画效果应用到position:absolute/fixed元素上,控制动画速度可以选择requestAnimationFrame
避免使用css表达式
将频繁重绘或重排的节点设置为图层
css3硬件加速(GPU加速),可以使用transform、opacity、filters这些动画不会引起重绘重排,但对于background-color还是会引起重排重绘。

总结

重排是更新了元素的几何属性后,浏览器重新触发布局,更新完整的渲染流程的过程;
重绘是修改了元素的绘制属性后,浏览器会直接进入图层绘制阶段,再执行之后的渲染流程的过程;
重排必定会发生重绘,但重绘不一定会发生重排;
合成是修改一个既不要布局也不要绘制的属性后,渲染引擎直接跳过布局和图层绘制的阶段,只执行后续的合成操作的过程。
减少重排重绘可以优化web性能,浏览器通过队列机制来优化。