跳到主要内容

重绘和重排

了解!重绘(Repaint)和重排(Reflow)是浏览器渲染过程中的两个重要概念,它们直接影响网页的性能。

1. 重绘(Repaint)

重绘是指浏览器 重新绘制 页面中已经显示的元素的过程。它发生在元素的视觉外观(样式)发生变化时,比如颜色、背景、阴影等。重绘不会影响元素的布局,只是会重新计算元素的样式并重绘到屏幕上。

例如:

  • 改变元素的 colorbackground-colorbordervisibility 等属性。

举个例子:

div {
background-color: blue;
}

改变 background-color 会导致浏览器 重绘 元素,但不会引起布局的变化。

2. 重排(Reflow)

重排(也叫回流)是指 元素的几何属性发生变化时,浏览器需要 重新计算元素的位置、尺寸、布局,并重新渲染整个页面的布局。重排比重绘更加消耗性能,因为它涉及到更复杂的计算和更新。

常见的会引发 重排 的操作:

  • 改变元素的 widthheightpaddingmarginborderdisplayposition 等属性。
  • 增加、删除、移动 DOM 元素。
  • 浏览器窗口尺寸的变化(即页面尺寸的变化,导致所有元素的重新布局)。

举个例子:

div {
width: 100px;
height: 100px;
}

widthheight 被改变时,浏览器需要 重新计算 元素的位置、尺寸,可能会导致整个页面的布局变化(因此是重排)。

重绘和重排的区别

特性重绘(Repaint)重排(Reflow)
触发条件仅仅是元素的样式属性(如颜色、背景、字体等)发生变化元素的几何属性(如位置、尺寸)发生变化,或者 DOM 结构发生变化
性能开销较小,只涉及元素的外观,不影响布局较大,因为需要重新计算布局,涉及更多的 DOM 树计算
影响范围影响的是视觉样式的更新影响的是整个布局的更新,可能影响整个页面的显示
例子改变 colorbackground-colorborder-color 等属性改变 widthheightdisplayposition 等属性

为什么重排和重绘会影响性能?

  • 重排 会导致 整个文档树的重新计算。例如,浏览器需要计算元素的几何尺寸、位置、布局,甚至可能需要重新渲染屏幕上的其他元素,这会影响性能。
  • 重绘 相对较轻,但当频繁发生时,仍然会导致浏览器需要重新绘制元素,尤其是在复杂的页面中,可能会导致用户体验变差。

如何减少重绘和重排?

为了提升性能,应该尽量减少不必要的重绘和重排。以下是一些优化建议:

1. 避免频繁改变布局相关属性

  • 尽量避免频繁改变元素的 widthheighttopleftmarginpadding 等,这些都会触发 重排
  • 尽量将这些操作合并进行,比如在修改多个元素的样式时,先在内存中做更改,最后一次性更新 DOM。

2. 使用 transformopacity 来替代布局相关的样式

  • 对于动画和交互效果,使用 transformopacity 来进行动画控制,因为这两个属性不会引起重排,只会引起重绘,性能开销小。
  • 例如,使用 transform: translate() 来移动元素,而不是修改 lefttop 等属性。
/* 使用 transform 来避免重排 */
div {
transform: translateX(100px);
}

/* 使用 top/left 会引发重排 */
div {
left: 100px;
}

3. 批量修改 DOM 元素

  • 避免在 JavaScript 中对 DOM 元素进行逐个修改,因为每次 DOM 操作都会触发浏览器的重排或重绘。
  • 尽量将多次 DOM 操作合并为一次操作,或者使用文档片段(DocumentFragment)来批量修改。

4. 避免使用 offsetHeightoffsetWidth 等读取布局属性

  • 读取这些属性会导致浏览器 强制同步布局,即强制计算出当前元素的尺寸和位置,从而可能会触发重排。
  • 尽量避免频繁访问这些属性,尤其是在每次渲染时访问。
// 不要在每个循环中读取 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 操作,尽量使用 transformopacity 等不会引起重排的属性进行动画。
  • 通过合理的优化手段,减少不必要的布局计算和渲染,可以显著提高页面的性能和用户体验。