重绘与重排
什么是重排(Reflow)?
重排(Reflow)
重排(Reflow) 是指当 DOM 的几何信息发生变化 时,浏览器需要重新计算元素的布局位置及大小,并将其放置到正确的位置。
触发重排的场景
- 添加、删除或更新 DOM 节点。
- 改变元素的几何属性(如
width
、height
、padding
、margin
、border
等)。 - 元素的显示状态从
display: none
切换为可见。 - 浏览器窗口大小变化。
- 动画导致元素的几何属性变化(如移动、缩放等)。
- 修改字体大小或内容改变导致文本流重新计算。
💡 注意:重排是性能开销最大的操作,因为它会导致整个页面或部分页面重新计算布局。
什么是重绘(Repaint)?
重排(Reflow)
重绘(Repaint) 是指当 元素的外观发生变化(如颜色、背景、阴影等),但不影响其几何属性时,浏览器会重新绘制这些元素的外观。
触发重绘的场景
- 改变元素的颜色(如
color
、background-color
)。 - 改变元素的边框样式(如
border-color
)。 - 设置元素的透明度(如
opacity
)。 - 元素的显示状态从
visibility: hidden
切换为可见。
⚠️ 区别:重绘不影响布局,因此它的性能开销通常小于重排。
重排和重绘的关系
- 重排必然会触发重绘:因为页面布局的改变会影响元素的外观。
- 重绘不一定会触发重排:如果仅仅是外观变化(如颜色),不会影响布局。
🚨 总结:重排的性能消耗更高,因此在开发中应尽量避免频繁触发重排操作。
如何优化避免重排与重绘?
1. 减少 DOM 操作
- 合并多次 DOM 更新:集中修改 DOM,而不是逐条操作。
- 离线更新 DOM:使用
DocumentFragment
或克隆节点在内存中操作,完成后一次性更新到 DOM 中。
2. 避免循环中操作 DOM
将 DOM 属性值提取到变量中,在循环外部完成修改。
3. 使用合适的显示属性
- 使用
visibility: hidden
代替display: none
,因为前者只触发重绘,而后者会触发重排。 - 为频繁变化的元素设置
position: absolute
或fixed
,可以减少对其他元素的影响。
4. 动画优化
- 使用
transform
和opacity
来实现动画,因为它们不会触发回流或重绘。 - 启用 GPU 加速,通过
translate3d
或will-change
提升性能。
5. 避免使用 Table 布局
Table 的布局依赖于其子元素的几何信息,任何改动都会导致整个表格重新计算布局。
6. 减少样式计算和重排
- 避免频繁读取会触发回流的属性(如
offsetWidth
、offsetHeight
等),可以将其缓存到变量中。 - 使用
class
切换样式而不是逐条修改样式属性。
提升合成层的性能优化
合成层是浏览器单独为某些元素创建的图层,可以有效减少重排和重绘的开销。
如何提升元素为合成层?
- 使用
will-change
属性。 - 使用 3D 变换(如
translate3d
)。
合成层的优点
- GPU 优化:合成层的位图会交由 GPU 合成,比 CPU 处理更快。
- 局部重绘:合成层只会重绘自身,不会影响其他层。
- 避免回流:
transform
和opacity
等效果不会触发重排和重绘。
总结
在浏览器渲染过程中,重排和重绘是不可避免的,但可以通过优化代码减少它们的频繁触发。以下是关键点总结:
- 重排比重绘性能开销更大,应尽量减少重排操作。
- 使用合适的优化策略:如集中修改样式、缓存属性值、使用合成层等。
- 利用 GPU 加速和 CSS 动画,提升页面的渲染性能。
🚀 性能优化建议:减少 DOM 操作与回流重排,使用现代化的开发工具和框架(如 React 和 Vue)可以帮助开发者更高效地优化页面性能和用户体验。