在进入主题之前,先来了解一下浏览器的渲染过程,及动画执行的像素渲染过程。 以 Chrome 为例:
渲染过程主要包括以下几个过程(Chrome 浏览器):
- Parse Html ---HTML 解析
- Recalculate Style ---重新计算样式 Style(不包含布局 Layout)
- Layout ---计算布局位置信息
- Rasterizer ---光栅化(针对图形栅格化) 耗时
- Paint ---展示文档中可见的部分
- Image Decode ---图片解码,把图片解析到浏览器上显示
- Image Resize ---图片大小重置 耗时
- Composite Layers ---合并图层,输出页面到屏幕
像素渲染流水线
所写的 Web 页面最终以像素的形式在浏览器屏幕上呈现,要经历以下 5 个步骤
- JS/CSS --通过 JS/CSS 改变样式
- Style --计算样式
- Layout --计算布局
- Paint --绘制
- Composite --图层合并输出
理论上,页面的每一帧都是结过上述的流水线处理之后渲染出来的,但并不意味着页面每一帧的渲染都需要经过上述五个步骤的处理。 实际上,对视觉变化效果的一个帧的渲染,有三种常用的流水线:
- 发生重排 Layout 的情况:如改变元素的 width,position,操作 dom
- 发生重绘 Paint 的情况:如改变元素的 color,background
- 没有引发重排及重绘的情况:
从性能上看,第一种最差,第三种最好。
针对 animation 性能的优化建议
-
@keyframe 中尽量选择不会引起重排及重绘的元素属性:相关属性具体参考css triggers
-
不是所有属性动画消耗的性能都一样,其中消耗最低的是transform和opacity两个属性(当然还有会触发 Composite 的其他 CSS 属性),其次是Paint相关属性。
- 使用 box-shadow 作为变化属性
- 使用 opacity 作为变化属性
-
建议:使用 transform 的 translate 替代 margin 或 position 中的 top、right、bottom 和 left,同时使用 transform 中的 scaleX 或者 scaleY 来替代 width 和 height。
-
-
避免将 animation-iteration-count 设置为 infinite
-
间隔性动画:如提交按钮,在点击后,出现 loading 动画。可以在正常状态将 loading 元素隐藏,只有点击后才显示 loading。这样可以在正常状态屏蔽掉动画,减少渲染次数。
-
CSS 实验属性: will-change
- 告知浏览器该元素会有哪些变化,这样浏览器可以在元素属性真正发生变化之前提前做好对应的优化准备工作
-
CSS 新属性: contain
- 允许开发者声明当前元素和它的内容尽可能的独立于 DOM 树的其他部分。这使得浏览器在重新计算布局、样式、绘图或它们的组合的时候,只会影响到有限的 DOM 区域,而不是整个页面。
参考