求star

开源不易,喜欢请点个star吧

Ocean Han
955 字
5 分钟
回流和重绘
2023-04-20

浏览器渲染的大致流程#

TIP

​ 在 HTML中,每个元素都可以被视为一个’盒子’,在浏览器解析渲染过程中,会涉及到回流和重绘:

  • 回流(重排): 布局引擎根据各种样式计算每个盒子在页面上的大小和位置等,也就是几何信息
  • 重绘:根据计算好的几何信息,浏览器对每个盒子进行绘制

浏览器渲染机制

  • 解析HTML,生成DOM树,解析CSS,生成CSSOM
  • 将DOM树和CSSOM结合,生成渲染树(render tree)
  • Layout(回流): 根据生成的渲染树,进行回流,得到节点的几何信息
  • Painting(重绘): 根据得到的几何信息以及渲染树,得到节点的绝对像素
  • Display: 将像素发送给GPU,展示在页面上

回流和重绘的触发时机#

回流#

TIP

​ 回流这一阶段,主要是计算节点的几何信息,所以当页面布局和几何信息发生变化的时候,就会触发回流,比如下面的情况:

  • 页面一开始渲染的时候(无法避免)
    • 因为页面一开始相当于是空白的没有元素,后面添加了元素使页面布局发生变化
  • 添加或删除DOM元素
  • 显示或隐藏DOM元素
  • 元素的位置发生变化
  • 元素的尺寸发生变化(如大小宽高、边距等)
  • 浏览器窗口尺寸变化
    • 因为回流是根据视口的大小来计算节点的几何信息的
  • 获取一些特定的属性值
    • 比如: offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight。这些属性值都需要通过即时计算得到,所以浏览器为了获得这些值,也会进行回流

重绘#

TIP
  • 触发回流一定会发生重绘
  • 颜色的修改
  • 阴影的修改
  • 文本方向的修改等

浏览器优化机制#

TIP

​ 由于每次回流(重排)都会造成额外的计算消耗,所以大多数浏览器会通过 队列化修改并批量执行来优化重排过程。浏览器会将修改操作放到队列中,直到过了一段时间或者操作达到了设置的阈值,才会清空队列。

​ 当你获取布局信息的操作的时候,会强制队列刷新,包括前面讲到的offsetTop等方法都会返回最新的数据。因此浏览器不得不清空队列,触发回流重绘来返回正确的值

如何减少回流和重绘的发生#

TIP
  • 如果要给同个元素同时设置多个样式,使用类名去合并样式,然后通过添加/删除类名来达到目的
  • 避免设置多项内联样式
  • 对于复杂的动画效果,对其设置position: fixed / absolute尽可能使元素脱离文档流,从而减少对其他元素的影响
  • 使用css3硬件加速,可以让transformopacityfilters这些动画不会引起回流重绘
  • 避免使用 CSS 的 JavaScript 表达式
  • 在使用JavaScript动态插入多个节点时,可以使用DocumentFragment(文档碎片)。创建后一次性插入,避免多次的渲染
  • 有时候,我们需要修改元素的布局,那么就很有可能用到上文提到过的那些需要即时计算的属性(offsetTop、offsetLeft…),如果每次循环都进行获取,性能比较糟糕,可以使用变量进行缓存,计算完毕后再提交给浏览器发出重计算请求
  • 我们还可以通过通过设置元素属性display: none,将其从页面上去掉,然后再进行后续操作,这些后续操作也不会触发回流与重绘,这个过程称为离线操作
回流和重绘
https://blog.oceanh.top/posts/frontend/回流和重绘/
作者
Ocean Han
发布于
2023-04-20
许可协议
CC BY-NC-SA 4.0
最后修改时间
2024-08-10 10:08:49