在页面渲染过程中,会有几个阶段:
- 生成
dom树 - 生成
cssom树 - 计算元素在屏幕上的具体位置,生成
layout tree - 遍历
layout tree,生成元素的渲染顺序,这里主要是针对可以产生不同层级的z-index属性 - 接下来是
paint的过程:再将布局树渲染之前,还有一个分层的操作。将页面分层不同的layers,然后对每一层都进行栅格化,将栅格化之后的单元信息传给GPU,保存在GPU内存中,然后GPU利用这些信息拼出整个页面。
🚨🚨🚨 多图警告
1. 哪些属性会导致分层呢?
一个一个来测试,并不是列举的属性能都导致分层。
可以通过Chrome的控制台的更多工具找到 layers选项
z-index
html,css代码如下:
<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;
}
结果如下:
很明显,z-index并不能产生分层,它是在上述的步骤中第四步产生影响,跟composition中的分层是不同的概念。
定位
.box {
width: 100px;
height: 100px;
position: absolute;
left: 0;
background-color: pink;
}
定位也不能产生分层
will-change✅
在上面定位基础之上,给box的样式中添加 will-change: left,就能看到box会出现分层:
transform✅
translate2d的时候,不会产生分层,translate3d的时候会。
canvas✅
添加canvas元素,以及绑定上下文,并绘制图案。(只有绘制了才能分层。)
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'green';
ctx.fillRect(10, 10, 150, 100);
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;
}
7.opacity + transition ✅
opacity: 0.5;
transition: opacity 1s ease;
// 动态改变opacity值
setTimeout(() => {
document.querySelector('.box').style.opacity = 1
}, 2000)
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
}
}
接下来,给box中添加 will-change: left;,然后神奇的事情发生了:
注意两种图中的Paint count, 第一张图中的数值一直在递增,表明docuement的一直在重绘,而第二张只重绘了一次。而过多的重排和重绘会导致页面卡顿。
虽然分层能够提升整个渲染性能。但是不能滥用分层,太多的分层控制会导致更多的内存消耗,也给GPU带来负担,从而影响整个渲染过程,导致适得其反。最佳实践,在动画上使用。
参考资料: