重学 JS | 通过无限循环动画案例理解 CSS3 动画与 JS 动画

聊到动画我们首先想到CSS3,JS动画,哪种在实现无限循环更优呢?这里总结下涉及的知识点,以及基本无限循环动画的实现,还有优劣势分析。



下面以如下HTML元素,





实现元素从左往右,再从右往左无限循环的动画











#box {
width: 100px;
height: 100px;
background: red;
position: relative;
}



    <span>
        <span>
            <span>CSS3动画</span>
        </span>
    </span>


    <span>
        <span>
            <span>animation</span>
        </span>
    </span>

看看CSS3 animation动画属性。

    <code>animation: </code>


    <code>name </code>


    <code>duration</code>


    <code>timing-function </code>


    <code>delay </code>


    <code>iteration-count </code>


    <code>direction </code>


    <code>fill-mode</code>


    <code>play-state;</code>

<ol><li>
        animation-name:指定要绑定到选择器的关键帧的名称,即@keyframes 动画指定的名称,或者none。
    </li>
    <li>
        animation-duration: 定义动画完成一个周期需要多少秒或毫秒。
    </li>
    <li>
        animation-timing-function:通过定义速度曲线,指定动画将如何完成一个周期。(速度曲线:定义动画从一套 CSS 样式变为另一套所用的时间)
    </li>
    <li>
        预定义的速度曲线
    </li>
</ol>linear | ease | ease-in | ease-out | ease-in-out
2. 三次贝塞尔曲线

    <span>
        <span>
            <span>cubic-bezier(</span>
        </span>
    </span>
    <span>
        <span>
            <i>
                <span>n</span>
            </i>
        </span>
    </span>
    <span>
        <span>
            <span>,</span>
        </span>
    </span>
    <span>
        <span>
            <i>
                <span>n</span>
            </i>
        </span>
    </span>
    <span>
        <span>
            <span>,</span>
        </span>
    </span>
    <span>
        <span>
            <i>
                <span>n</span>
            </i>
        </span>
    </span>
    <span>
        <span>
            <span>,</span>
        </span>
    </span>
    <span>
        <span>
            <i>
                <span>n</span>
            </i>
        </span>
    </span>
    <span>
        <span>
            <span>),值的范围是0到1的数值</span>
        </span>
    </span>

<ol><li>
        animation-delay: 定义动画什么时候开始
    </li>
    <li>
        animation-iteration-count:  定义动画应该播放多少次,值为infinite,则无限次播放,为数字,则播放几次。
    </li>
    <li>
        animation-direction: 是否循环交替反向播放动画,定义只播放1次,则该属性不起作用。值为alternate,则奇数次正常播放,偶数次,向后播放。
    </li>
    <li>
        animation-fill-mode: 当动画不播放时(当动画完成时,或当动画有一个延迟未开始播放时),要应用到元素的样式。
    </li>
    <li>
        animation-play-state:指定动画是否正在运行或已暂停,值为paused|running。
    </li>
</ol>
    <span>
        <span>
            <span>@keyframes</span>
        </span>
    </span>

关键帧的意思,定义动画在不同阶段的状态。通常将它分为0%,50%,100%三个状态。

 相关理论知识学完了,看下以下代码实现:

#box {
animation: loopanimation 4s infinite alternate;
-webkit-animation: loopanimation 4s infinite alternate;
-moz-animation: loopanimation 4s infinite alternate;
-o-animation: loopanimation 4s infinite alternate;
-ms-animation: loopanimation 4s infinite alternate;
}
@keyframes loopanimation {
0% {
left: 0px;
}
50% {
left: 100px;
}
100% {
left: 0px;
}
}

    <span>
        <span>
            <span>优缺点</span>
        </span>
    </span>

优点:
浏览器可以对动画进行优化,相应的点如下:
<ol><li>
        浏览器使用与requestAnimationFrame 类似的机制,相应机制在下面JS动画中介绍。
    </li>
    <li>
        通过GUP提高动画性能(强制使用硬件加速)
    </li>
</ol>缺点:
<ol><li>
        CSS3动画运行过程难以把控,无法附加事件进行回调函数绑定,它只能暂停,同时它也不能在动画中寻找特定的时间点、反转动画,或者变换时间尺度。
    </li>
    <li>
        不利于编写复杂动画,容易造成代码冗长。
    </li>
</ol>
    <span>
        <span>
            <span>JS动画</span>
        </span>
    </span>

编写动画函数:
<pre>letanimationFun =function(){

letbox =document.getElementById(‘box’)
letpos =0// 起始位置
letend =500// 终点位置
letstep =10// 步长
lettoRight =true// 方向
returnfunctionanimate(box,pos,end,step,toRight){
if(toRight){
if(pos=end?false:true
}
}else{
pos-=step
toRight = pos<=0?true:false
}
box.style.left = pos+'px'
}
}

    <span>
        <span>
            <span>setInterval</span>
        </span>
    </span>

通过setInterval实现循环,时间为1000/60,因为大多数浏览器渲染是60帧/s
<pre>letanimate = animationFun()

lettimer =setInterval(function(){
animate()
},1000/60)

    <span>
        <span>
            <span>requestAnimationFrame</span>
        </span>
    </span>

requestAnimationFrame 是个动画框架,它的优势如下:
<ol><li>
        会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。
    </li>
    <li>
        在隐藏或不可见的元素中requestAnimationFrame不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。
    </li>
</ol><pre>letanimate = animateFun()

functionanimloop(){
animate();
window.requestAnimationFrame(animloop);
}
animloop()

    <span>
        <span>
            <span>优缺点</span>
        </span>
    </span>

优点:
<ol><li>
        JS动画控制能力强,可以在动画播放中对其进行开始、暂停、中止、取消等操作。
    </li>
    <li>
        JS动画能实现更复杂的动画效果,比如:曲线运动、冲击闪烁等。
    </li>
    <li>
        CSS3有兼容性问题,而JS大多数没有兼容问题。
    </li>
</ol>缺点:
<ol><li>
        JavaScript在浏览器的主线程中运行,而主线程中还有其它需要运行的JavaScript脚本、样式计算、布局、绘制任务等,对其干扰导致线程可能出现阻塞,从而造成丢帧的情况。
    </li>
    <li>
        代码复杂度高于CSS动画。
    </li>
</ol>
    <span>
        <span>
            <span>总结</span>
        </span>
    </span>

最后再解答个问题?为啥CSS3动画比JS动画更流畅?
渲染线程分为主线程和合成器线程。如果CSS动画只改变transform、opacity两种属性,则此时动画直接在合成器线程完成。采用JS动画,会在主线程进行,然后触发合成器线程进行下步操作。若此时JS线程执行昂贵的任务,主线程繁忙,会造成失帧堵塞,此时采用CSS动画更流畅。因此,CSS3动画比JS动画流畅是基于一定前提的:
<ol><li>
        JS在执行昂贵的任务
    </li>
    <li>
        同时CSS动画不触发layout或paint。
    </li>
</ol>因为触发了重绘或者重排,都需要主线程进行Layer树的重新计算,这时动画都会阻塞后续操作。不触发重绘重排的属性有:transfrom|opacity|perspective-origin|perspective|backface-visibility

 至此,我们借助实现无限循环的动画例子,学习了CSS3动画以及JS动画,以及之前的优劣势。简而言之,不需要中间过程控制,只是简单状态切换,选CSS动画。若需复杂动画、进行过程控制等,选JS动画。