避免回流和重绘
约 501 字大约 2 分钟
2024-08-14
回流(Reflow)与重绘(Repaint)
概念
- 回流(Reflow):当 DOM 的几何属性(宽度、高度、边距、位置)发生变化时,浏览器重新计算布局
- 重绘(Repaint):当元素的视觉属性(颜色、背景、边框)变化但不影响布局时,浏览器重新绘制
回流必定触发重绘,但重绘不一定回流。
触发回流的属性
| 类型 | 属性 |
|---|---|
| 尺寸 | width, height, padding, margin |
| 显示 | display, visibility |
| 定位 | position, top, left, right, bottom |
| 字体 | font-size, font-weight |
| 浮动 | float |
| 窗口 | scrollTop, scrollLeft, scrollWidth, scrollHeight, getComputedStyle |
仅触发重绘的属性
- color, background, background-image
- border-style, border-radius
- outline, outline-color, outline-width
- box-shadow, text-shadow
优化策略
1. 批量修改 DOM
// 使用文档片段
const fragment = document.createDocumentFragment();
items.forEach(item => {
const li = document.createElement('li');
li.textContent = item;
fragment.appendChild(li);
});
list.appendChild(fragment); // 一次回流
// 先隐藏再显示
element.style.display = 'none';
// DOM 操作
element.style.display = 'block'; // 一次回流
// clone 后操作
const clone = element.cloneNode(true);
// 在 clone 上操作
element.parentNode.replaceChild(clone, element);2. 使用 CSS 类批量修改
// 避免
element.style.width = '100px';
element.style.height = '100px';
element.style.margin = '10px';
// 推荐
element.classList.add('large', 'spaced');3. 使用 transform 和 opacity
/* 避免使用 width/height/left/top 动画 */
@keyframes move {
from { left: 0; }
to { left: 100px; } /* 触发回流 */
}
/* 推荐使用 transform */
@keyframes move {
from { transform: translateX(0); }
to { transform: translateX(100px); } /* 仅触发合成 */
}4. 避免频繁读取布局属性
// 反面示例:强制同步布局
const width = element.offsetWidth; // 触发回流
element.style.width = width + 10 + 'px';
const height = element.offsetHeight; // 又触发回流
// 优化:缓存值
const width = element.offsetWidth;
const height = element.offsetHeight;
requestAnimationFrame(() => {
element.style.width = width + 10 + 'px';
element.style.height = height + 10 + 'px';
});5. 使用 will-change 提示浏览器
.element {
will-change: transform;
transform: translateZ(0); /* 强制 GPU 加速 */
}6. 使用 CSS contain 属性
.container {
contain: layout style paint;
}性能检测
使用 Chrome DevTools 的 Performance 面板观察回流和重绘:
- 打开 DevTools → Performance
- 勾选 "Enable advanced render instrumentation"
- 录制用户操作
- 查看 Rendering 事件统计
参考文章:
