简单记录下回流 reflow 和重绘 repaint

1,226 阅读4分钟

回流和重绘想必都听过,每当说起性能优化的时候,都会聊到这个话题,遂记录下,以加深下记忆,希望之后再探讨时能想起一些细节而不至于事后再去网上搜索,同时也希望能够让正在看的你对回流和重绘有一些思考。

💭本文首发掘金: 简单记录下回流 reflow 和重绘 repaint

浏览器引擎渲染过程

开始之前先熟悉下浏览器渲染 DOM 的一个大致过程,主要分了四步:

  1. 解析 HTML 结构并构建出 DOM 树

  2. 构建 render 树

  3. 布局 render 树

  4. 绘制 render 树

详细的过程如下:

  1. 分析 HTML 结构,构建出 DOM

  2. 分析 CSS 样式,解析出样式规则表

  3. DOM 树和样式规则表关联,从而构建出 render 树(构建的过程称之为 Attachment

    1. 从 DOM 树的根节点开始,遍历每一个可见的节点

      • head, meta, title 等节点会被忽略,不会被添加到 render 树中,同样不影响渲染的输出

      • 样式为 display: none 同样也被忽略【1】

    2. 对每一个可见的节点,找到并匹配相对应的样式规则

  4. 开始布局 render 树上的节点(也就是确定出每个节点的坐标和大小)

  5. 有了坐标后,浏览器就会遍历 render 树,进而绘制出各个节点

注: 【1】 区别于 visibility: hiddenvisibility: hidden 会将元素设置为不可见,同时占据页面上的一块空间,而 display: none 则是将节点从整个 render 树中移除,可以将其理解成不是布局中的一部分。

什么是回流和重绘

在刚刚看到的绘制 render 树的过程中,可能会发生的两种渲染行为,我们分别称之为回流,重绘。

回流(reflow)

当 DOM 节点的几何形状发生变化时,(就比如说 DOM 节点的宽高发生了变化)

浏览器将检查所有其他任何受影响的区域,并重新计算其尺寸和位置

再自动排列 DOM 节点,最后再重新绘制,这个过程称为回流/重排(reflow)。

可以理解为 DOM 整容了,就会触发回流(reflow)

重绘(repaint)

若 DOM 节点的图像、颜色和阴影发生了变化,即不涉及任何排版、布局问题时,则跳过布局,直接绘制,这个过程称为重绘(repaint)。

可以理解为 DOM 只是简单的化妆了,才会触发重绘(repaint)

触发场景

回流(reflow)

  1. js 操作 DOM 时
  2. 设置 style 属性 / 改变元素可见性( display: none
  3. 元素 width/heightfontSizeborder 的修改
  4. animationtransition
  5. 读取了元素自身的某些属性( offsetWidth, offsetHeight, getComputedStyle() 等 )
  6. scroll 滚动事件
  7. 窗口大小的改变

重绘(repaint)

  1. 颜色的修改
  2. 文本方向的修改
  3. 阴影的修改

结论

  • reflow 的触发会重新计算节点的尺寸和位置,而且还有可能触发其 children 节点、 parent 节点和其他节点的 reflow,开销较大
  • repaint 不一定会触发 reflow,但是 reflow 必然导致 repaint
  • 由于 repaint 不会影响布局,所以较于 reflow 来说开销很低

实际上,浏览器可以选择等到线程结束后再重新回流并修改 DOM。这意味着,如果这些修改在同一个线程中足够快地发生了,那么它们可能只会产生一个 reflow

也就是说,大部分现代浏览器都已经对 reflow 做了一些优化,它会等到足够多的数量时做一次批处理,再来触发 reflow

可以看这篇文章详细讲解了内部的细节 Keeping the number of reflows to a minimum

一些优化

  • 尽量减少 DOM 操作
  • 减少 DOM 嵌套层级
  • 尽量不使用内联样式
  • 避免使用 table 进行布局,table 中每个元素的大小以及内容的改动,都会导致整个 table 的重新计算。改用 div 可有效避免不必要的 reflowrepaint
  • 对于那些复杂的动画,对其设置 position: fixed/absolute,尽可能地使元素脱离文档流,从而减少对其他元素的影响

参考资料:

Render-tree Construction, Layout, and Paint

vue核心之虚拟DOM(vdom)

Rendering: repaint, reflow/relayout, restyle

Keeping the number of reflows to a minimum