【浏览器渲染】浏览器图层与重绘重排

2021/09/30 14:11:45

浏览器渲染 Dom 流程

  1. 获取 DOM 后分割为多个图层
  2. 对每个图层的节点计算样式结果 (Recalculate style--样式重计算)
  3. 为每个节点生成图形和位置 (Layout--重排,回流)
  4. 将每个节点绘制填充到图层位图中 (Paint--重绘)
  5. 图层作为纹理上传至 GPU
  6. 组合多个图层到页面上生成最终屏幕图像(复合图层) (Composite Layers--图层重组)

重绘(Repaint)

重绘是一个元素外观的改变所触发的浏览器行为,例如改变 outline、背景色等属性。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。

重绘不会带来重新布局,所以并不一定伴随重排。

重绘是以图层为单位,如果图层中某个元素需要重绘,那么整个图层都需要重绘。

触发重绘的属性

凡是对外观有影响的属性。

  color             background            outline-color
  border-style      background-image      outline
  border-radius     background-position   outline-style
  visibility        background-repeat     outline-width
  text-decoration   background-size       box-shadow

重排(Reflow)

渲染对象在创建完成并添加到渲染树时,并不包含位置和大小信息。计算这些值的过程称为布局或重排。

重排必然伴随着重绘。

触发重排的属性

  width             top             text-align      min-height
  height            bottom          overflow-y      white-space
  padding           left            font-weight     vertival-align
  margin            right           overflow        clear
  display           position        font-family     border
  border-width      float           line-height

图层

合理的创建单独图层可以提高性能,但是滥用的话反而会导致更严重的性能问题。

图层创建的条件

  1. 拥有具有 3D 变换的 CSS 属性
  2. 使用加速视频解码的元素 (<video>)
  3. <canvas>节点
  4. CSS3 动画的节点
  5. 拥有 CSS 加速属性的元素(will-change)
  6. 拥有 3D (WebGL) 上下文或加速的 2D 上下文的 元素
  7. 混合插件(如 Flash)
  8. 有动画效果的元素
  9. 元素有一个包含复合层的后代节点(如果有一个元素 A,它的兄弟元素在复合层中渲染,而这个兄弟元素的 z-index 小于 A,那么元素 A(不管是不是应用了硬件加速样式)也会被放到复合层中。)
  10. 浏览器会给复合层之后的所有相对或绝对定位的元素都创建一个复合层来渲染。

图层的作用

将一些动画效果放到一个单独的图层中可以提高重绘、重排的效率。

优化方案

使用 transform 代替 absolute 完成位置移动

元素位置移动变换时尽量使用 CSS3 的 transform 来代替对 top left 等的操作。

变换(transform)和透明度(opacity)的改变仅仅影响图层的组合。

控制单独图层显示状态时用 opacity 来代替 visibility

使用 visibility 不触发重排,但是依然重绘。

直接使用 opacity 即触发重绘,又触发重排(GPU 底层设计如此!)。

opacity 配合图层使用,即不触发重绘也不触发重排。

透明度的改变时,GPU 在绘画时只是简单的降低之前已经画好的纹理的 alpha 值来达到效果,并不需要整体的重绘。

不过这个前提是这个被修改 opacity 的元素本身必须是一个图层。

不要频繁操作 DOM

将多次改变样式属性的操作合并成一次操作,不要一条一条地修改 DOM 的样式,预先定义好 class,然后修改 DOM 的 className。

替换元素内容时现将待替换内容全部处理好然后一次替换。

将 DOM 离线(display:none)后再修改

由于 display 属性为 none 的元素不在渲染树中,对隐藏的元素操作不会引发其他元素的重排。

如果要对一个元素进行复杂的操作时,可以先隐藏它,操作完成后再显示。这样只在隐藏和显示时触发 2 次重排。

使用 documentFragment

https://www.cnblogs.com/echolun/p/10098752.htmlopen in new window

不要在循环中获取 DOM 属性值

在获取一些 DOM 属性时,浏览器为了返回最新的信息需要刷新内部队列,频繁操作会导致性能问题。

会触发刷新的属性

  1. offsetTop, offsetLeft, offsetWidth, offsetHeight
  2. scrollTop/Left/Width/Height
  3. clientTop/Left/Width/Height
  4. width,height

将复杂动画放到同一个图层中

避免生成过多的图层

页面中的图层过多会导致卡顿,避免不必要的图层。

这个open in new window 页面中,浏览器生成了 2000 多个图层,滚动操作非常卡顿,勾选复选框之后将这些图层合并成一个,可以明显感受到滚动变得顺畅了。

用硬件加速提升页面性能

CSS 的 animations, transforms 以及 transitions 不会自动开启 GPU 加速,而是由浏览器的软件渲染引擎来执行。

开启硬件加速可以提高动画的流畅度。

可以触发硬件加速的 CSS 属性

浏览器会为 3D 变化开启硬件加速,对于不需要这些属性的元素可以通过设置 translateZ(0) 值来欺骗浏览器,从而使用硬件加速。

transform: translateZ(0);

例子

原版在这里open in new window

浏览器会给复合层之后的所有相对或绝对定位的元素都创建一个复合层来渲染。

开启硬件加速不一定会创建复合图层

打开 chrome layers 可以看到【添加动画】时后面的所有元素都会创建复合图层,【硬件加速】时并不会创建
  • hello world
    2015-09
  • hello world
    2015-09
  • hello world
    2015-09
  • hello world
    2015-09
  • hello world
    2015-09

参考

浅谈浏览器的图层与重绘重排(详细),以及如何用于性能优化open in new window

CSS3 开启硬件加速及利弊open in new window