看图说话:页面渲染过程中的分层

528 阅读3分钟

在页面渲染过程中,会有几个阶段:

  1. 生成dom
  2. 生成 cssom
  3. 计算元素在屏幕上的具体位置,生成layout tree
  4. 遍历layout tree,生成元素的渲染顺序,这里主要是针对可以产生不同层级的 z-index 属性
  5. 接下来是paint的过程:再将布局树渲染之前,还有一个分层的操作。将页面分层不同的layers,然后对每一层都进行栅格化,将栅格化之后的单元信息传给GPU,保存在GPU内存中,然后GPU利用这些信息拼出整个页面。

🚨🚨🚨 多图警告

1. 哪些属性会导致分层呢?

一个一个来测试,并不是列举的属性能都导致分层

可以通过Chrome的控制台的更多工具找到 layers选项

  1. z-index

htmlcss代码如下:

<div class="container">
   <div class="box">box</div>
</div>
.container {
  position: relative;
  width: 300px;
  height: 300px;
  border: 1px solid #e1e1e1; 
}

.box {
  width: 100px;
  height: 100px;
  z-index: 2;
  background-color: pink;  
}

结果如下:

image.png

很明显,z-index并不能产生分层,它是在上述的步骤中第四步产生影响,跟composition中的分层是不同的概念。

  1. 定位
.box {
  width: 100px;
  height: 100px;
  position: absolute;
  left: 0;
  background-color: pink;  
}

image.png

定位也不能产生分层

  1. will-change

在上面定位基础之上,给box的样式中添加 will-change: left,就能看到box会出现分层:

will-change.png

  1. transform

translate2d的时候,不会产生分层,translate3d的时候会。

  1. canvas

添加canvas元素,以及绑定上下文,并绘制图案。(只有绘制了才能分层。)

image.png

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

ctx.fillStyle = 'green';
ctx.fillRect(10, 10, 150, 100);

image.png

  1. z-index的特殊情况: 如果兄弟元素.box分层,当前元素.box-two比兄弟元素zIndex要高,且位置上有重叠时,当前元素也会产生分层 ✅
.box {
  width: 100px;
  height: 100px;  
  position: absolute;
  left: 0;
  will-change: left;
  z-index: 4;    
  background-color: pink;
}


.box-two {
  position: absolute;  
  left: 0;
  top: 10px;
  z-index: 5;
  background: green;
}

image.png

7.opacity + transition

    opacity: 0.5;
    transition: opacity 1s ease;
    // 动态改变opacity值
   setTimeout(() => {
      document.querySelector('.box').style.opacity = 1
    }, 2000)

layer.gif

  1. filter

filter情况比价特殊,必须开启了硬件加速之后,才能分层。

。。。如果还有其他情况,欢迎补充。

2. 那分层有什么用呢?

还是用图说话:

box加上一个动画

.box {
  width: 100px;
  height: 100px;
  background-color: pink;
  position: absolute;
  left: 0;
  animation: loop 3s ease Infinite;
}

@keyframes loop {
  0% {
    left: 0
  }
  50% {
    left: 200px
  }
  100% {
    left: 0
  }
}

image.png

接下来,给box中添加 will-change: left;,然后神奇的事情发生了:

image.png

注意两种图中的Paint count, 第一张图中的数值一直在递增,表明docuement的一直在重绘,而第二张只重绘了一次。而过多的重排和重绘会导致页面卡顿。

虽然分层能够提升整个渲染性能。但是不能滥用分层,太多的分层控制会导致更多的内存消耗,也给GPU带来负担,从而影响整个渲染过程,导致适得其反。最佳实践,在动画上使用

参考资料: