在移动端的一些h5页面或其他地方经常要使用css动画,但是在pc端看着好好的动画到移动端上却出现了卡顿,遂搜集了一些有关css动画性能优化方面的资料。
GPU
现代浏览器大都利用了GPU来加速网页渲染。GPU是专用于图形渲染的芯片,它擅长做如下事情:
- 绘制位图到屏幕上
- 对图片进行处理,例如:修改位置、旋转和缩放等等
知道GPU擅长什么之后,让我们以Chrome为例子分析下如何利用GPU来加速页面渲染的。
众所周知,Chrome的特性之一是多进程,每个页面标签都有一个独立的Render进程。Render进程中包含了主线程和合成线程。
主线程:
- Javascript的执行
- CSS样式计算
- 计算Layout
- 将页面元素绘制成位图(paint)
- 发送位图给合成线程
合成线程
- 将位图发送给GPU
- 计算页面的可见部分和即将可见部分(滚动)
- 通知GPU绘制位图到屏幕上(draw)
这里的layout就是具体计算每个元素的大小和位置,paint就是将元素绘制在屏幕上。
那么GPU渲染是如何优化动画的呢?
如果某个元素处于以下状态:
- 当一个元素位于HTML文档的最外层(元素)
- 当一个元素position不为initial,并且拥有一个z-index值(不为auto)
- 当一个元素被设置了opacity,transforms, filters, css-regions, paged media等属性。
那么这个元素就会产生一个新的渲染层,这时候执行动画,此元素将不会触发layout和paint过程,只需通知GPU按照现有的位图,按照相应的变换在独立的渲染层中输出,然后再合并输出。这个过程并不需要主线程CPU的参与。
而当我们使用left,padding,margin,JavaScript,jQuery等方式来执行动画,那么CPU需要重新计算每一帧,元素的位置,外观,重新定位元素,repaint,即进行layout和paint过程,然后才生成位图,传给GPU渲染。
因此为了达到前者的效果,通常会用translate3d,translateZ,或者是opacity < 1等来强制开启硬件加速。
GPU弊端
GPU虽然擅长处理图像,但是它也有瓶颈。连接CPU和GPU之间的带宽是有限的,如果一次更新的层太多,则很容易就达到GPU的瓶颈,影响到动画的流畅度。所以我们需要控制层的数量和层paint的次数。
总结
- 动画中尽量少使用能触发layout和paint的CSS属性,使用更低耗的transform、opacity等属性,尽量避免left/padding/background-position等
- 尽量减少或者固定层的数量,不要在动画过程中创建层