回流与重绘

浏览器渲染过程

参考:https://zhuanlan.zhihu.com/p/561696825

  1. 解析 HTML 和计算样式(parsing and style calculation)把 HTML 解析成 DOM,把 CSS 解析成 CSSOM,DOM 和 CSSOM 合并渲染树(render tree)。

  2. 渲染树(render Tree)有 DOM 的结构和每个节点的样式,但这还不足以呈现页面,还需要计算节点在画面上的大小和位置,这个过程称为布局,并且这个过程中会产生一个布局树。

  3. 绘制拥有 DOM、样式和布局仍然不足以呈现画面,浏览器仍然必须判断元素的绘制顺序。

  4. 在前三个步骤中,浏览器已经获得了渲染页面所需的资讯,但为了提供整体渲染效率,浏览器会再透过合成,将资讯渲染到画面上。合成事一种将页面的哥哥部分分成图层(layers)的拘束,这个技术会在合成线程这个单独的线程执行。这个过程完成之后,还会再产生一个图层树,最终才渲染到画面上。

回流和重绘

当网页的结构、大小或位置发生变化时,浏览器需要重新计算的集合属性(如宽高、位置),这个过程称为回流。浏览器会重新构建渲染树并重新布局,可能还伴随重绘。

触发场景:

  • 添加、删除 DOM 节点;

  • 改变元素尺寸、位置(如 width, height, padding, margin, display, position 等);

  • 读取引起回流的属性,如:offsetTop, offsetHeight, scrollTop, getComputedStyle()

  • 操作样式时未使用合适的合并手段(如:一次设置多个 style);

当元素的视觉样式发生变化(如颜色、背景、边框等)但没有引起布局变化时,浏览器会重新绘制该元素,称为重绘。表现为仅更新像素,而不涉及布局计算。

触发场景:

  • 修改 color, background-color, visibility, border-color 等不会影响布局的样式

  • 更改元素的 className 但只影响了视觉;

性能影响

  • 回流 > 重绘 > JS 运算:回流开销最大,因为它可能影响整个 DOM 树甚至触发多次重绘。

  • 回流过程中会阻塞浏览器渲染和用户交互,影响页面流畅性。

优化建议

1. 避免频繁操作 DOM

  • 将多次 DOM 操作合并为一次(如使用 DocumentFragment)

  • 批量操作时先脱离文档流,如:element.style.display = 'none'

2. 减少读取触发同步布局的属性

  • 尽量避免立即访问 offsetXXXscrollXXX 等属性,或在批量读取前缓存需要的值

3. 使用 CSS3 合理替代

  • transform, opacity 替代 top/left, width/height,可避开回流,仅触发 GPU 加速的重绘或合成层变化

4. 避免逐帧修改样式

  • 在动画中使用 requestAnimationFrame 来协调更新时机

  • 合理使用 will-change 提示浏览器预优化

最后更新于

这有帮助吗?