当更新了元素的几何属性,浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排,也称为“回流”。
例如通过 JS 或 CSS 修改了元素的宽度和高度,浏览器会触发重新布局,解析之后的一系列子阶段,这个过程就叫重排。
渲染树的节点发生改变,影响了该节点的几何属性,导致该节点位置发生变化,此时就会触发浏览器重排并重新生成渲染树。重排意味着节点的几何属性改变,需重新计算并生成渲染树,导致渲染树的全部或部分发生变化。
重排需要更新完整的渲染流水线,所以开销也是最大的。
任何会改变元素的位置和尺寸大小的操作,都会触发重排。常见的例子如下:
几何属性:包括布局、尺寸等可用数学几何衡量的属性。
获取布局信息的属性如下:
频繁获取这些属性会强制清空浏览器的重排队列,建议避免频繁使用。
浏览器渲染界面是基于流式布局模型的,所以触发重排时会对周围的 DOM 重新排列,影响的范围分两种:
从根节点 html 开始对整个渲染树重新布局。
<body>
<div class="hello">
<p><strong>Name:</strong>BDing</p>
<h5>male</h5>
<ol>
<li>loving</li>
</ol>
</div>
</body>
上面代码中的 p 节点发生重排时,它的父节点 div 和 body 也会发生重排,甚至 h5 和 ol 节点也会受到影响。
对渲染树的某部分或某一渲染对象进行重新布局。
例如:将一个 DOM 元素的宽高等几何信息写死,然后在 DOM 元素内部触发重排,就只会重新渲染该 DOM 元素内部的元素,而不会影响到外界。
更新了元素的绘制属性,但没有改变布局,重新把元素外观绘制出来的过程叫做重绘。例如更改某些元素的背景颜色。
重绘并没有引起元素几何属性的改变,所以就直接进入绘制阶段,然后执行之后的一系列子阶段。
和重排相比,重绘省去了布局和分层阶段,所以执行效率会比重排操作要高一些。
重排一定会伴随重绘,重绘却不一定伴随重排。
包括界面、文字等可用状态向量描述的属性
重排和重绘在操作节点样式时频繁出现,同时也存在很大程度上的性能问题。重排成本比重绘成本高得多,因为一个节点的重排可能导致子节点、兄弟节点或祖先节点的重排,所以我们要尽可能减少重排次数、重排范围。
Table 布局可能很小的一个改动就会造成整个 table 重排。通常可用 ul、li、span 等标签取代 table 系列标签生成表格。
浏览器的 CSS 解析器解析 css 文件时,对 CSS 规则是从右到左匹配查找,样式层级过多会影响重排重绘效率。应尽量避免写过于具体的 CSS 选择器,保证层级扁平。
将节点设置为 video 或 iframe,或为节点添加 will-change 属性,可以阻止节点的渲染行为影响别的节点。
动画速度越快,重排次数越多。浏览器刷新频率为 60Hz,即每 16.6ms 更新一次,而 requestAnimationFrame()正是以 16.6ms 的速度更新一次。
可以使用绝对定位,让其脱离文档流,避免父元素及后续元素频繁重排。
使用新的类名预定义节点样式,在适合时机一次性动态替换原来的类名集合,避免频繁触发重排。
频繁访问布局属性会导致浏览器强制清空队列,进行强制同步布局。应在循环外使用变量保存不会变化的 DOM 映射值。
使元素脱离文档流,对其进行多次修改,最后再将元素带回到文档中。可以通过 display 隐藏、DocumentFragment 或复制节点等方式实现。
使用 CSS3 硬件加速,可以让 transform、opacity、filters、will-change 这些动画不会引起重排重绘,但其它属性如 background-color 还是会引起重排重绘。
注意:为太多元素使用 CSS3 硬件加速会导致内存占用较大,GPU 渲染字体会导致抗锯齿无效。