重绘和重排
了解!重绘(Repaint)和重排(Reflow)是浏览器渲染过程中的两个重要概念,它们直接影响网页的性能。
1. 重绘(Repaint)
重绘是指浏览器 重新绘制 页面中已经显示的元素的过程。它发生在元素的视觉外观(样式)发生变化时,比如颜色、背景、阴影等。重绘不会影响元素的布局,只是会重新计算元素的样式并重绘到屏幕上。
例如:
- 改变元素的
color
、background-color
、border
、visibility
等属性。
举个例子:
div {
background-color: blue;
}
改变 background-color
会导致浏览器 重绘 元素,但不会引起布局的变化。
2. 重排(Reflow)
重排(也叫回流)是指 元素的几何属性发生变化时,浏览器需要 重新计算元素的位置、尺寸、布局,并重新渲染整个页面的布局。重排比重绘更加消耗性能,因为它涉及到更复杂的计算和更新。
常见的会引发 重排 的操作:
- 改变元素的
width
、height
、padding
、margin
、border
、display
、position
等属性。 - 增加、删除、移动 DOM 元素。
- 浏览器窗口尺寸的变化(即页面尺寸的变化,导致所有元素的重新布局)。
举个例子:
div {
width: 100px;
height: 100px;
}
当 width
或 height
被改变时,浏览器需要 重新计算 元素的位置、尺寸,可能会导致整个页面的布局变化(因此是重排)。
重绘和重排的区别
特性 | 重绘(Repaint) | 重排(Reflow) |
---|---|---|
触发条件 | 仅仅是元素的样式属性(如颜色、背景、字体等)发生变化 | 元素的几何属性(如位置、尺寸)发生变化,或者 DOM 结构发生变化 |
性能开销 | 较小,只涉及元素的外观,不影响布局 | 较大,因为需要重新计算布局,涉及更多的 DOM 树计算 |
影响范围 | 影响的是视觉样式的更新 | 影响的是整个布局的更新,可能影响整个页面的显示 |
例子 | 改变 color 、background-color 、border-color 等属性 | 改变 width 、height 、display 、position 等属性 |
为什么重排和重绘会影响性能?
- 重排 会导致 整个文档树的重新计算。例如,浏览器需要计算元素的 几何尺寸、位置、布局,甚至可能需要重新渲染屏幕上的其他元素,这会影响性能。
- 重绘 相对较轻,但当频繁发生时,仍然会导致浏览器需要重新绘制元素,尤其是在复杂的页面中,可能会导致用户体验变差。
如何减少重绘和重排?
为了提升性能,应该尽量减少不必要的重绘和重排。以下是一些优化建议:
1. 避免频繁改变布局相关属性
- 尽量避免频繁改变元素的
width
、height
、top
、left
、margin
、padding
等,这些都会触发 重排。 - 尽量将这些操作合并进行,比如在修改多个元素的样式时,先在内存中做更改,最后一次性更新 DOM。
2. 使用 transform
和 opacity
来替代布局相关的样式
- 对于动画和交互效果,使用
transform
和opacity
来进行动画控制,因为这两个属性不会引起重排,只会引起重绘,性能开销小。 - 例如,使用
transform: translate()
来移动元素,而不是修改left
、top
等属性。
/* 使用 transform 来避免重排 */
div {
transform: translateX(100px);
}
/* 使用 top/left 会引发重排 */
div {
left: 100px;
}
3. 批量修改 DOM 元素
- 避免在 JavaScript 中对 DOM 元素进行逐个修改,因为每次 DOM 操作都会触发浏览器的重排或重绘。
- 尽量将多次 DOM 操作合并为一次操作,或者使用文档片段(
DocumentFragment
)来批量修改。
4. 避免使用 offsetHeight
、offsetWidth
等读取布局属性
- 读取这些属性会导致浏览器 强制同步布局,即强制计算出当前元素的尺寸和位置,从而可能会触发重排。
- 尽量避免频繁访问这些属性,尤其是在每次渲染时访问。
// 不要在每个循环中读取 offsetHeight
let height = div.offsetHeight; // 可能会触发重排
5. 使用 requestAnimationFrame
来优化动画
- 在 JavaScript 中进行动画时,使用
requestAnimationFrame
来确保浏览器可以优化渲染帧,避免不必要的重绘和重排。
function animate() {
// 执行动画
requestAnimationFrame(animate); // 优化动画帧的渲染
}
6. 避免频繁的 DOM 更新
- 如果你的代码中存在大量 DOM 元素的频繁添加或删除操作,尽量合并这些操作,或者使用虚拟 DOM(例如 React 中的虚拟 DOM) 来优化渲染。
7. 使用 will-change
提示浏览器优化
will-change
是一个 CSS 属性,可以告诉浏览器某个元素即将发生变化,浏览器可以提前做一些优化,减少重排的成本。只在必要时使用,避免滥用,因为过多的will-change
会消耗性能。
div {
will-change: transform;
}
8. 减少 JavaScript 中的 style
操作
- 不要频繁地通过 JavaScript 修改元素的
style
属性,因为这会直接导致 重排 或 重绘。尽量通过 批量修改 或使用 class 切换来更改样式。
总结
- 重绘 和 重排 都是浏览器渲染页面时必不可少的过程,但它们对性能的影响不同。重排 比 重绘 更为消耗性能。
- 为了提高性能,应该尽量减少重排和重绘,特别是避免频繁修改布局相关的样式属性,合并 DOM 操作,尽量使用
transform
、opacity
等不会引起重排的属性进行动画。 - 通过合理的优化手段,减少不必要的布局计算和渲染,可以显著提高页面的性能和用户体验。