- 2016年的老文,搬运存档用 -
基本大家已经了解优化动画性能的套路了: 开启硬件加速的同时,又要小心硬件加速后页面层级的坑,导致 CPU 和内存大量消耗,硬件加速没有起到正向的作用,反而对页面造成负担。还要熟练使用 Chrome Dev Tools 检测性能,把帧率提高。
前情提要
开启硬件加速的元素会有自己的复合层(layer),不过复合层是个很容易造成额外问题的家伙。有些开启了硬件加速的页面,性能没法看,比如这位提到的。为什么层多了,性能反而差了呢?开启硬件加速的全称应该是开启 GPU 硬件加速,GPU 是擅长做图形图像处理的,当有一个元素要做动画了,浏览器会生成一个复合层(composited layer),动画是在这个复合层上让 GPU 完成的。复合层吃内存,CPU 和 GPU 之间还有通信成本。在内存和 CPU、GPU 处理能力尚且比不上 PC 的大多数移动设备上,性能自然就差了。跳坑的方法就是一句:减少复合层的出现。
根据 13 年的 Accelerated Rendering in Chrome - The Layer Model 这篇文章(到了16年,触发复合层的情况多了不少,chrome 也变得智能了好多……笔者还在研究,过一段时间会 po 成果),我们知道,在以下情况中,CSSOM足够复杂的前提下(所以可能现在写一个简单的 demo 页面以下条件不再适用了),会有层的出现:
1. CSS 3D transform 或者 3D perspective transform
2. 加速视频解码的 <video>
元素
3. 被 3D 渲染(WebGL)的或者在 2D 上下文中的 <canvas>
4. flash 或类似的插件
5. 在 opacity 或者 transform 上做动画的元素
6. CSS filter
7. 子元素有自己的层的,父级元素也会有复合层
8. 存在兄弟元素的 z-index 比较小且在复合层的元素
<video>
、<canvas>
、flash 还有 filter 我们暂且不考虑。我们通常会用第一个方法主动地创建层,但往往因为 z-index 没有处理或者没有处理好,由于规则7和规则8(加粗部分),结果产生了一堆预期之外的层,而且很明显,规则7还是无法避免的。所以现在我们的目的就转变成了:如何合理设置元素的 z-index,减少同级元素之间的影响。
开始
- demo 用的是不久以后才会上线的微云等级页面
- 使用的浏览器是 Chrome 51.0.2704.106 (正式版本)
- 请在 Dev Tools 中勾选 Show layers borders 和 Enable paint flashing(Animations 也可以勾选起来)。Mac 上的开启路径是 cmd alt I > ESC:
动画过程非常简单,分为四步: 1. 进度条增长 2. 当前等级位置高亮 3. 文案弹出 4. 撒彩带
z-index 在动画性能里的影响很大,所以先来个侧视图吧: 当前等级结构在等级标志中,彩带在文案弹窗中;图中灰色和黑色部分都是没有动画的,彩色的标识是有动画的
所以按照以下条件: 1. 做动画的元素开启硬件加速 2. 暂时不对 z-index 做处理 3. 结合上文中会触发复合层生成条件 4. 除去页面上因为动画暂时还没有出现的元素。
以进度条为例,根据规则7 规则8可以推出以下元素,也会有复合层,然而它们其实是静态的并不需要放进复合层里: 1. 进度条的父级元素 – 进度条容器; 3. 根据 DOM 结构,在进度条容器后面的结构 – “静态内容”也会有自己的复合层; 2. 进度条的同级但是 z-index 略高的元素 – 等级标志。
其中因为视觉设计的关系,等级标志肯定会在进度条的上面,所以这个复合层是没法避免了(红豆泥……?),所以我们暂时不处理。由进度条容器导致的两个复合层,其实只需要把父元素 – 进度条容器的 z-index 提高,就能解决同级复合层影响的问题。
其他
上面是分析了页面上的第一个出现的动画,有木有发现,复合层的出现很像 js 的冒泡过程,而我们要做的就是尽可能的阻止动画的“冒泡”。z-index 越高的元素,它做动画时所波及的元素越少。在与flash、canvas还有video无关的页面上,总结一下原则: 1. 动画元素的 z-index 要高于同级无动画元素 2. 动画元素的父级 z-index 要高于它(父级)的同级元素
彩蛋
“等级标志肯定会在进度条的上面,所以这个复合层是没法避免了”,真的吗?
其实是可以避免的啦~
用 will-change 就好了!关于 will-change 的优缺点,我在下一篇会讲到~ stay tunnnnnned ヽ(✿゚▽゚)ノ
代码语言:javascript复制.processor-bar {
will-change: width;
/* transform: translate3d(0, 0, 0); */
-webkit-transition: width 650ms cubic-bezier(.33,1.06,.27,1.09) 100ms;
transition: width 650ms cubic-bezier(.33,1.06,.27,1.09) 100ms;
}
参考资料
- Accelerated Rendering in Chrome - The Layer Model
- 提高 HTML5 画布性能
- html5 功能 - 图形