浏览器的重绘与回流
chenpeng 2020-11-30 浏览器渲染流程
# 1.回流
当对 DOM 的修改引发 DOM 几何尺寸变化的时候,会发生回流,每个页面至少有一次回流(页面第一次加载的时候)
以下操作会触发回流:
- DOM 元素的几何属性发生变化,例如
width、height、margin、padding、border、top、bottom、left、right等 - 使 DOM 节点发生增减或者移动
- 读写
offset族、scroll族和client族属性的时候,浏览器为了获取这些值,会进行回流操作 - 调用
window.getComputedStyle方法
回流过程
如果 DOM 结构发生变化,需要重新生成 DOM 树

# 2.重绘
当对 DOM 的修改导致样式发生变化,没有影响几何属性的时候,会发生重绘
重绘过程
由于没有导致几何属性的变化,因此不需要重新布局

因此,重绘不会导致回流,而回流一定会导致重绘
# 3.合成
利用 CSS3 的transform、opacity、filter这些属性就可以实现合成的效果,也就是GPU加速
# GPU加速的原因
在合成的情况下,会直接跳过布局和绘制流程,直接进入非主线程处理的部分,即直接交给合成线程处理。交给它处理有两大好处:
- 能够充分发挥
GPU的优势。合成线程生成位图的过程中会调用线程池,并在其中使用GPU进行加速生成,而GPU 是擅长处理位图数据的。 - 没有占用主线程的资源,即使主线程卡住了,效果依然能够流畅地展示。
# 4.如何减少回流和重绘
- 避免频繁使用 style,而是采用修改 class 的方式
- 使用 createDocumentFragment 进行批量的 DOM 操作
- 对于 resize、scroll 等进行防抖/节流处理
- 使用
visibility替换display: none,因为前者只会引起重绘,后者会引发回流 - 避免触发同步布局事件,我们在获取
offsetWidth这类属性的值时,可以使用变量将查询结果存起来,避免多次查询,每次对offset/scroll/client等属性进行查询时都会触发回流 - 对于复杂动画效果,使用绝对定位让其脱离文档流,复杂的动画效果会频繁地触发回流重绘,我们可以将动画元素设置绝对定位从而脱离文档流避免反复回流重绘
- 添加
will-change:transform,让渲染引擎为其单独实现一个图层,当这些变换发生时,仅仅只是利用合成线程去处理这些变换,而不牵扯到主线程,大大提高渲染效率。当然这个变化不限于tranform, 任何可以实现合成效果的 CSS 属性都能用will-change来声明