最近公司做一个H5抽奖活动,要求将中奖名单(??不存在的)显示在页面中,效果类似直播平台的弹幕一样飘过 。心想简单啊,直接定位用animate动画就解决了,然而…
问题来了,问题来了,问题来了!在测试的时候,发现部分安卓机型出现卡卡卡卡顿的现象,实际动画效果引起强烈不适,有一种撸多了的感觉…Android 姬妮怎么老是出问题呀(╯‵□′)╯︵┻━┻ 。
经过一番周折,两遁空门,叁叁来迟,似李狗贼终于让我找见了解决卡顿的方法 。
方案:
尽量使用 transform 当成动画处理,避免使用 height,width,margin,padding 等;
要求较高时,可以开启浏览器开启GPU硬件加速
webkit-transform: translate3d( 0,0,0 );
-moz-transform: translate3d( 0,0,0 );
-ms-transform: translate3d( 0,0,0 );
-o-transform: translate3d( 0,0,0 );
transform: translate3d( 0,0,0 );
那到底是为什么 Android 姬会出现卡顿的现象呢?为什么亲儿子 IOS 没有受到遗传呢?这后面究竟是道德的伦桑还是人性的扭曲?欢迎收看《 走进科学 - Android 下的C3动画》。
令人吃鲸的真相
从浏览器的引擎工作原理方面
深入浏览器理解 CSS animations 和 transitions 的性能问题 一文中提到,现代的浏览器通常会有两个重要的执行线程,这2个线程协同工作来渲染一个网页:主线程和合成线程 。
一般情况下,主线程负责:
- 运行 JavaScript
- 计算 HTML 元素的 CSS 样式。
- 页面的布局
- 将元素绘制到一个或多个位图中
- 将这些位图交给合成线程
相应地,合成线程负责:
- 通过 GPU 将位图绘制到屏幕上
- 通知主线程更新页面中可见或即将变成可见的部分的位图
- 计算出页面中哪部分是可见的
- 计算出当你在滚动页面时哪部分是即将变成可见的
- 当你滚动页面时将相应位置的元素移动到可视区域
使用 height,width,margin,padding,top,left 占用主线程比较耗时。而使用 transform 浏览器只需要一次生成这个元素的位图,并在动画开始的时候将它提交给GPU去处理 。
通过DevTools从文档对象模型到像素级别的观察
下图是 Chrome 浏览器中动画的 timeline,瀑布流越高,浏览器为了计算每个像素,就做的越多。
由此也能验证以上得出的结论 。
文章 High Performance Animations 提到:
We’re going to cut straight to the chase. Modern browsers can animate four things really cheaply: position, scale, rotation and opacity. If you animate anything else, it’s at your own risk, and the chances are you’re not going to hit a silky smooth 60fps.
现代浏览器在完成 position,scale,rotation,opacity 四种属性的动画时,消耗成本较低 。
捉急的项目证实
为了验证以上的理论,我将两种写法做了比对 。
下图是我之前的方法,使用定位改变 right 的值使元素从右到左移动,但是可以看到这种写法的 FPS 平均只有 30 。我们知道每秒 60 帧是最适合人眼交互的,FPS 小于 60 人眼能明显感觉的到,这就是为什么卡顿的原因 。
下图使用了 transform 方法改变 translateX 的值,FPS 明显高过 60 帧 ,惊不惊喜? 意不意外?
总结
为了做到兼容性好,流畅度高的动画,一定要对自己的代码做好优化,尽可能将动画元素absolute化以避免影响文档树,造成大面积重新计算layout 。动画处理使用浏览器渲染快的 transform 属性,尽量避免改变 height,width,margin,padding 等,要求较高时还可以开启浏览器 GPU 硬件加速( transform: translate3d( 0,0,0 ) ) 。
PS: