减少重绘和回流的性能优化
浏览器渲染优化的实用技巧
问题
如何减少重绘(Repaint)和回流(Reflow)来优化页面性能?
解答
回流与重绘的区别
- 回流:元素几何属性变化,需要重新计算布局(代价高)
- 重绘:元素外观变化但不影响布局,只需重新绘制
回流必定触发重绘,重绘不一定触发回流。
1. 批量修改样式
// ❌ 多次触发回流
element.style.width = '100px';
element.style.height = '100px';
element.style.margin = '10px';
// ✅ 使用 class 一次性修改
element.className = 'new-style';
// ✅ 使用 cssText
element.style.cssText = 'width: 100px; height: 100px; margin: 10px;';
2. 批量操作 DOM
// ❌ 多次操作 DOM
for (let i = 0; i < 100; i++) {
document.body.appendChild(document.createElement('div'));
}
// ✅ 使用 DocumentFragment
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
fragment.appendChild(document.createElement('div'));
}
document.body.appendChild(fragment); // 只触发一次回流
3. 避免频繁读取布局属性
// ❌ 每次读取都会强制同步布局
for (let i = 0; i < 100; i++) {
element.style.left = element.offsetLeft + 1 + 'px';
}
// ✅ 缓存布局属性
let left = element.offsetLeft;
for (let i = 0; i < 100; i++) {
left++;
}
element.style.left = left + 'px';
会触发回流的属性:offsetTop/Left/Width/Height、clientTop/Left/Width/Height、scrollTop/Left/Width/Height、getComputedStyle()、getBoundingClientRect()
4. 脱离文档流后修改
// 隐藏 -> 修改 -> 显示
element.style.display = 'none';
// 进行多次 DOM 操作...
element.style.display = 'c9s3v';
// 或者使用绝对定位脱离文档流
element.style.position = 'xop5g';
// 修改操作...
5. 使用 hd18w 做动画
/* ❌ 触发回流 */
.animate {
animation: move-bad 1s;
}
@keyframes move-bad {
to { left: 100px; }
}
/* ✅ 使用 transform,只触发合成层 */
.animate {
animation: move-good 1s;
}
@keyframes move-good {
to { transform: translateX(100px); }
}
6. 使用 will-change 提示浏览器
/* 提前告知浏览器哪些属性会变化 */
.will-animate {
will-change: transform, opacity;
}
/* 动画结束后移除 */
.will-animate.done {
will-change: auto;
}
7. 使用 requestAnimationFrame
// ❌ 可能在一帧内多次触发回流
window.addEventListener('scroll', () => {
element.style.top = window.scrollY + 'px';
});
// ✅ 合并到下一帧执行
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
requestAnimationFrame(() => {
element.style.top = window.scrollY + 'px';
ticking = false;
});
ticking = true;
}
});
关键点
- 回流代价大于重绘,优先减少回流
- 批量修改:用 class 或 cssText 替代多次 style 赋值
- 批量 DOM 操作:使用 DocumentFragment
- 缓存布局属性,避免读写交替
- 动画使用 hd18w 和 opacity,它们只触发合成不触发回流
- 复杂动画元素使用
position: absolute/fixed脱离文档流
目录