一、重绘(Repaint)与回流(Reflow)的定义与区别
1. 重绘(Repaint)
- 定义:当元素的外观属性(如颜色、背景、可见性等)发生变化,但不影响其在文档流中的布局和几何尺寸时,浏览器会重新绘制该元素,此过程称为重绘。
- 触发条件:
- 修改颜色、背景色、边框颜色、透明度、阴影等非几何属性。
- 修改
visibility
属性(如visibility: hidden
)。
- 性能影响:重绘不涉及布局计算,因此开销较小。
2. 回流(Reflow / Layout)
- 定义:当元素的布局、几何属性(尺寸、位置、结构)发生变化时,浏览器需重新计算所有受影响元素的几何信息,并更新渲染树,此过程称为回流。
- 触发条件:
- 增删/移动 DOM 节点。
- 修改元素尺寸(宽高、边距、边框)或位置(
top
、left
)。 - 窗口大小改变、字体大小改变、内容变化(如文本长度)。
- 读写
offsetWidth
、scrollTop
等布局属性(强制同步计算)。
- 性能影响:回流涉及整个或部分文档的重新布局计算,开销比重绘大 10 倍以上。
3. 核心区别与联系
特性 | 回流(Reflow) | 重绘(Repaint) |
---|---|---|
触发原因 | 布局/几何属性变化 | 外观属性变化(不影响布局) |
计算范围 | 部分或整个文档树 | 仅需更新元素外观 |
性能开销 | 高(需重新布局) | 低(仅重绘像素) |
关联性 | 回流必触发重绘 | 重绘不触发回流 |
示例 | 修改 width 、display: none | 修改 color 、visibility: hidden |
引用说明:
二、优化重绘与回流的方法
1. 减少 DOM 操作
- 批量修改:使用
DocumentFragment
或离线 DOM(display: none
)进行批量操作,完成后一次性插入文档。 - 避免逐条修改样式:用
class
替代内联样式(如element.className = "new-style"
),或通过cssText
合并样式修改。
2. 优化样式与布局
- 使用 GPU 加速属性:
- 用
transform
替代top/left
(动画不触发回流)。 - 用
opacity
替代visibility
(opacity
可触发 GPU 合成)。
- 用
- 避免触发同步布局:
- 缓存布局属性:如将
offsetWidth
存入变量,避免重复读取。 - 避免循环中读写布局属性(如先读取所有值,再统一修改)。
- 缓存布局属性:如将
3. 分离渲染层
- 脱离文档流:为动画元素设置
position: absolute/fixed
,限制回流范围仅影响自身。 - 使用
will-change
:提示浏览器元素将独立渲染(如will-change: transform
)。
4. 规避高开销操作
- 避免
table
布局:table
的局部修改可能触发全局回流。 - 用
visibility
替代display: none
:display: none
触发回流 + 重绘;visibility: hidden
仅触发重绘。
- 慎用 CSS 表达式(
expression
) :每次渲染都会重新计算。
5. 利用浏览器优化机制
- 防抖/节流:对
resize
、scroll
事件进行节流,减少回流频率。 - 现代 CSS 方案:
- Flexbox/Grid 布局比传统布局回流更少。
- 使用
contain: strict
限制元素影响范围。
三、关键场景示例
1. 动画优化
// ❌ 低效:每次修改 top 触发回流
element.style.top = `${top++}px`;
// ✅ 高效:使用 transform(不触发回流)
element.style.transform = `translateY(${top}px)`;
2. 批量 DOM 操作
// ❌ 逐条插入节点触发多次回流
list.forEach(item => container.appendChild(item));
// ✅ 使用 DocumentFragment 批量插入
const fragment = document.createDocumentFragment();
list.forEach(item => fragment.appendChild(item));
container.appendChild(fragment);
3. 样式修改对比
// ❌ 多次修改内联样式
element.style.color = "red";
element.style.background = "blue";
// ✅ 通过 class 或 cssText 合并
element.className = "new-style";
// 或
element.style.cssText = "color:red; background:blue;";
四、总结
- 核心原则:回流 > 重绘 > 无操作,优先避免回流,其次减少重绘。
- 性能工具:使用 Chrome DevTools 的 Performance 面板检测回流/重绘事件,Layers 面板检查渲染层分离效果。
- 框架优化:在 Vue/React 中,
v-show
比重绘(仅修改display
),v-if
比回流(增删节点)更高效。
通过上述策略,可显著提升页面渲染性能,尤其在复杂交互或动画场景中效果显著。