重排和重绘
1. 举例说明什么是“重排”“重绘”和“合成”
- 重排:
- 当DOM的变化影响了元素的几何信息(元素的的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。
- 重排也叫回流,简单的说就是重新生成布局,重新排列元素。
- 重绘:
- 当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。
- 直接合成阶段:
- 更改一个既不要布局也不要绘制的属性,渲染引擎将跳过布局和绘制,只执行后续的合成操作,这个过程叫做合成;
2. 哪些实际操作会导致回流与重绘
- 重排:
- 页面初始渲染,这是开销最大的一次重排
- 添加/删除可见的DOM元素
- 改变元素位置
- 改变元素尺寸,比如边距、填充、边框、宽度和高度等
- 改变元素内容,比如文字数量,图片大小等
- 改变元素字体大小
- 改变浏览器窗口尺寸,比如resize事件发生时
- 激活CSS伪类(例如:
:hover) - 设置 style 属性的值,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow
- 重绘:
- 修改color
- 修改border-style、border-radius
3. “重排”“重绘”和“合成”哪一个开销最大
相较于重排操作,重绘省去了布局和分层阶段,所以执行效率会比重排操作要高一些。
合成是在在非主线程上合成,并没有占用主线程的资源,另外也避开了布局和绘制两个子阶段,所以相对于重绘和重排,合成能大大提升绘制效率。
4 如何规避回流与重绘
-
js中样式集中改变,避免逐条改变样式,使用类名去合并样式
// bad var left = 10; var top = 10; el.style.left = left + "px"; el.style.top = top + "px"; // 当top和left的值是动态计算而成时... // better el.style.cssText += "; left: " + left + "px; top: " + top + "px;"; // better el.className += " className"; -
分离读写操作,DOM 的多个读操作(或多个写操作),应该放在一起。不要两个读操作之间,加入一个写操作。
浏览器的渲染队列机制:
当我们修改了元素的几何属性,导致浏览器触发重排或重绘时。
它会把该操作放进渲染队列,等到队列中的操作到了一定的数量或者到了一定的时间间隔时,浏览器就会批量执行这些操作。
// bad 强制刷新 触发四次重排+重绘 div.style.left = div.offsetLeft + 1 + 'px'; div.style.top = div.offsetTop + 1 + 'px'; div.style.right = div.offsetRight + 1 + 'px'; div.style.bottom = div.offsetBottom + 1 + 'px'; // good 缓存布局信息 相当于读写分离 触发一次重排+重绘 var curLeft = div.offsetLeft; var curTop = div.offsetTop; var curRight = div.offsetRight; var curBottom = div.offsetBottom; div.style.left = curLeft + 1 + 'px'; div.style.top = curTop + 1 + 'px'; div.style.right = curRight + 1 + 'px'; div.style.bottom = curBottom + 1 + 'px'; -
将 DOM 离线
- 给元素设置
display:none,添加足够多的变更后,通过display属性显示。通过这种方式即使大量变更也只触发两次重排。 - 通过
documentFragment创建一个dom碎片,在它上面批量操作dom,操作完成之后,再添加到文档中,这样只会触发一次重排。
- 给元素设置
5. 如何在浏览器中查看页面渲染时间
打开开发者工具:点击 Performance 左侧有个小圆点 点击刷新页面会录制整个页面加载出来 时间的分配情况。
- 蓝色: 网络通信和HTML解析
- 黄色: JavaScript执行
- 紫色: 样式计算和布局,即重排
- 绿色: 重绘
哪种色块比较多,就说明性能耗费在那里。色块越长,问题越大