移动端动画的效率问题
最近工作很忙,好久没有发帖了。前些日子跳槽到一家新单位就接到了一个很难的工作项目。在这个项目中技术核心点是动画效率问题。经过了近半个月的攻关各种难题总算是搞定了。同时,对移动端浏览器对动画的解析能力有了一个更高的认知。在这里想和大家分享一下。有不足之处欢迎指正!
做移动前端的盆友应该都知道,动画特效方面,尤其兼容安卓系统,就和互联网端兼容IE6一样麻烦。好多效果不错的创意都因为不兼容安卓系统而夭折。归根到底还是因为安卓浏览器性能的问题。这里篇外话一下,安卓手机的硬件可以甩苹果一条街。但在浏览器上表现的则相反。现在安卓系统已经发展到android 4.X了.可分配给浏览器的内存还是少的可怜!貌似不足10%; 所以一些很流畅的动画效果在IOS上跑一点压力没有。但在android上跑卡的要命!希望android 5.0时可以多给点内存在浏览器上,尽量提升一下浏览器的性能比。
言归正传,在移动端动画效果上,使用css3动画要比jquery动画效率高的多。在安卓手机上表现尤其明显!所以移动端动画以css3动画为优先。
我们知道css3动画分为两大类: animation和transform,这两者根据实际项目需求来分别使用。前者为关键帧动画,后者为变换动画。关键帧动画多用于可循环动画。而变换动画多用于一次性动画。当然这也不是绝对的。两者是可以相互转换使用的。究竟这两者在移动端那个更省浏览器性能,我参考了大量的文档也没有得出什么结论来。总之个人认为差不多吧。关键还是代码写的是否合理。方法是否应用得当。
通过做这个实际项目的大量效果测试得出一些自己的观点。大家仅供参考。
第一,先说说transform:
比如有一个需求,我需要将一个整体元素从下至上移动到屏幕上,这里有很多办法来加以实现。举例:要想让一个元素动起来,我们需要给这个元素先加一个原始的动画样式;
#erjidiv{
position: absolute;
width: 100%;
heigth:600px;
top: 0px;
left: 0px;
-webkit-transform:translateY(100%);
-webkit-transition:-webkit-transform 0s 0s;
}
然后通过某些事件接口修改这个样式即可
$("#erjidiv").css({
"-webkit-transform":"translateY(0%)",
"-webkit-transition":"-webkit-transform 0.5s ease-out 1s",
})
这样通过位移Y轴translateY的方式.延迟1s 由快变慢的方式完成了动画。
在互联网中运用的CSS3样式。大家很习惯都使用 "-webkit-transition":"all 0.5s ease-out 1s",
但在移动端为了性能问题不推荐这么做。all所包含的是所有属性。如果只是某一处只运用了该动画的话。那么没有什么太大的区别,至少肉眼看不出来。但如果在同一时间实行多处元素动画的话。使用all属性就会有卡顿现象。而只写改变某个属性的话则该现象基本可以杜绝了。尤其在安卓上表现明显。所以此处我只使用了-webkit-transform属性。
有童靴会问,我改变其top的坐标值不是一样可以移动嘛;比如这样:
#erjidiv{
position: absolute;
width: 100%;
heigth:600px;
top: -600px;
left: 0px;
-webkit-transition:top 0s 0s;
}
$("#erjidiv").css({
"top":"0px",
"-webkit-transition":"top 0.5s ease-out 1s",
})
是的,这样依然可以达到该效果。但这么做显然在动画效率上不高。我参考了一些文章,说这么做效果还不如jquery动画效率高。这点我没有拿jquery动画和这个比较过。但这个和前者比较过。确实从流畅度来讲不如前者。尤其是同一时间多个元素同时执行动画。另外,像top、left、width、height等这些css基础属性在移动端不到迫不得已的情况下还是少参与动画的好。真的是很影响动画效率。我们使用css3的-webkit-transition的方式来做动画。与其门当户对配合的也应该是css3的属性-webkit-transform,两者完美结合才能在最大程度上提升动画效果。降低浏览器内存损耗。
此外,有童靴很可能使用互联网做动画的方式来做移动端动画(以前我也这么干过……)比如一个元素在静止状态时,采用了样式A。当它:hover时采用样式B。这样就实现了动画。把这种制作动画的方式搬到移动端一样也是可以的。其原理无非是两个样式的切换。那么根据这个原理上面的需求还可以变成这样:
.style1{
position: absolute;
width: 100%;
heigth:600px;
top: 0px;
left: 0px;
-webkit-transform:translateY(100%);
-webkit-transition:-webkit-transform 0s 0s;
}
.style2{
position: absolute;
width: 100%;
heigth:600px;
top: 0px;
left: 0px;
-webkit-transform:translateY(0%);
-webkit-transition:-webkit-transform 0.5s ease-out 1s;
}
$("#erjidiv").removeClass("style1").addClass("style2");
这样,通过移除和添加样式也可以实现上面的需求。那么这种办法是不是效率也比较高呢?
通过实际测试,当多个元素同时动画的时候。使用修改其样式也就是第一种办法要比这种添加和删除样式高效的多。所以,如果使用-webkit-transform这种动画方式的时候,最好的方案就是第一种,使用js修改其动画样式的效率是最高的。其他的方法效率都不高。不推荐在移动端上使用。
第二,再说说animation:
严格意义上来讲。transform方式不算是动画。只能算是变换。而animation才是正宗的动画。使用animation方式做动画,我们不得不提到关键帧@-webkit-keyframes。通过对其起始状态和终点状态之间的过程设置来形成动画。关于关键帧动画的使用就不举例说明了。百度一下有很多。
animation动画我个人理解多用于循环动画的地方。在这种动画需求下使用效率是最高的。优点是可以任意添加动作状态。缺点个人认为是不易进行控制。最大的缺陷是使用js无法获取到关键帧里面的动画状态参数。我想动态的改变关键帧里的变化数值,但无法做到。这里面的值只能写死或是使用百分比来代替具体数值。在移动端各种适配的需求下。很难有太灵活的变化。不过好像有js插件可以写关键帧动画。但我由于时间问题,还没有这方
面的详细研究。如果哪位同仁有这方面的经验,可以赐教一二。
之所以说它不易控制是没有一个好的启动切入点。目前我所知的办法就是当我要启动一个关键帧动画的时候,我需要给这个元素临时添加一个样式。
这个样式里写入了引用关键帧动画的-webkit-animation-name:XXX,然后设置周期、播放次数、变化方式等等参数。比如:
.fangda {
-webkit-animation-name: fangda;
-webkit-animation-duration: 1s;
-webkit-animation-timing-function: ease-out;
-webkit-animation-iteration-count: infinite;
}
@-webkit-keyframes fangda {
0% {-webkit-transform:scale(1,1)}
50% {-webkit-transform:scale(1.2,1.2); }
100% {-webkit-transform:scale(1,1); }
}
$("#erjidiv").addClass("fangda");
这样当我给元素添加样式后,动画开始启动。这种方法其实又回到了刚才在谈到transform方式时的用到的第三种方法。当我一瞬间同时使用好几个关键帧动画时,使用这种添加的方式没有修改其样式的效率高。会造成一瞬间卡顿的现象。这个尤以在安卓系统手机上表现明显。但第一种方法可以使用JS修改其样式。而关键帧动画却修改不了。
后来为了提高性能。想到不如先把样式加上。但我先让其暂停。想让它运行的时候再使用,于是乎想到了关键帧动画里有animation-play-state这个属性来控制暂停和运行。测试后果然可以。测试系统(android4.0以上,IOS6以上)。通过对比这种控制暂停,然后再让其启动的方式比单一添加样式的效率高很多。
.fangda {
-webkit-animation-name: fangda;
-webkit-animation-duration: 1s;
-webkit-animation-timing-function: ease-out;
-webkit-animation-iteration-count: infinite;
-webkit-animation-play-state:paused;
}
@-webkit-keyframes fangda {
0% {-webkit-transform:scale(1,1)}
50% {-webkit-transform:scale(1.2,1.2); }
100% {-webkit-transform:scale(1,1); }
}
$("#erjidiv").css("-webkit-animation-play-state","running");//根据需求再启动
通过以上的修正可以大大提高css3动画在移动端浏览器上效果的提升。即便在安卓浏览器上也能有较好的体现。
最后,再说说其他方面的个人心得;考虑到移动端浏览器性能问题。尽量避免同时多个动画。关键帧动画不用时,要么暂停掉。要么直接删除样式。个人更倾向于后者。有时候为了提高流畅度。必要时还要打开其渲染3d功能。在全局样式中进行设置如下样式:
-webkit-transform-style:preserve-3d;
-webkit-backface-visibility:hidden;
-webkit-transform:translate3d(0,0,0)
另外,浏览器在加载过程中会有一个预存渲染功能(专业术语叫什么忘记了,个人命名的便于理解),就是当要触发某些动画样式的时候,最好浏览器事先有过渲染,这样在执行起来的时候就会更加流畅。(因为节省了渲染时间)这也就很好的解释了为什么采用添加的方式没有改变其样式效率高!不添加动画样式时。浏览器事先是没有渲染的。添加时它需要临时渲染再执行动画,这需要时间。而改变样式却是在浏览器事先已经渲染好了动画,只不过不执行或是在暂停状态。需要时就可以马上启动。所以正是因为有了这个预存渲染的功能。再采用合适的方式时,就能缩短浏览器渲染时间,减少卡顿现象的产生的可能!真正的做到了提高移动端浏览器css3动画的效率问题!
-转自(前端网W3Cfuns-作者:oceanjauh)