帧动画函数steps()的解析

看完上一章的小伙伴们一定会有许多疑问,我明明定义了7帧:红橙黄绿青蓝紫。

为什么最后一帧紫色就是出不来呢?或者说必须做一些特殊处理才会出来呢?

steps()step-end分别代表什么含义呢?为什么一个带括号一个不带括号呢?

接下来我们将一一为大家揭晓答案。

1 steps()

step的英文原意是迈步,在这里可以理解为步骤。

既然是步骤,那就要指定分几步进行。所以括号里面就要写入一个数字,这个数字代表要分多少步来进行这段动画。

拿我们定义过的change-color动画来举例:

/* 定义动画:动画名(change-color) */ 
@keyframes change-color {
    /* 第1步 */ from /* 0% */ { color: red } /* 红 */
    /* 第2步 */ 16% { color: orange } /* 橙 */
    /* 第3步 */ 32% { color: yellow } /* 黄 */
    /* 第4步 */ 48% { color: green } /* 绿 */
    /* 第5步 */ 64% { color: cyan } /* 青 */
    /* 第6步 */ 80% { color: blue } /* 蓝 */
    /* 第7步 */ to /* 100% */ { color: purple } /* 紫 */
}

可以看到整个动画一共分为了七个步骤,那么是不是我们要在 step() 的括号里写上一个7呢?

  • steps(7)

你要是这么想的话,那你可就大错特错了。括号里面的数字不是指从0%到100%之间要被分成几步,

而是从第一步到第二步要被分为几步。同理,第二步到第三步,第三步到第四步,……,第N步到最后一步。

而我们想要的效果是:从红变橙、从橙变黄、……、再从蓝变紫。

所以我们只需要第一步到第二步、第N步到第N+1步之间只经历一个步骤就够了,所以应该写成:

  • steps(1)

steps()括号里一共可以写两个参数,第一个参数就是一个数字,代表把这次过渡分成几步。

第二个参数不写的话默认就是end,也就是说:

steps(1) = steps(1, end)

聪明的小伙伴们肯定想了,既然有end,那肯定就会有start嘛!

对没错,第二个参数除了end以外还可以写start。知道了它的第二个参数,就比较好理解step-start和start-end了。

2. step-start 和 step-end

其实step-startstep-end并不是什么新的概念,而是steps(1, start)和steps(1, end)实在是太常用了。

在编程界有个不成文的规定:某样事物如果使用次数很高的话通常都会出现一个缩写来替代他。

我知道有的小伙伴肯定会有疑问:这真的是缩写么?我怎么没感觉出来缩了几个字母呢?

其实如果仔细数一数的话还是缩了那么一点点的。

而之所以多出来两个缩写其实真实的目的并不是为了让你少打那么一两个字母,这样的缩写并没有什么太大意义。

他真正的意义在于单复数:

step-startstep-end里的step没有s!!!

steps()有s的!!!

学过英语的同学应该还记得单复数这个概念吧?(说不记得的同学,你的英语老师棺材板快压不住了)。

不记得没关系,咱们一起来复习一下:一样东西如果只有一个的话(比如你有一部手机)那么这个单词的后面就不用加s;

反之如果一样东西有很多的话(你有好几部手机)那么这个单词的后面就要加上s来表示。

steps()并不知道你会在括号里面写几,所以人家是带s的,复数!

那么问题来了,最最常用的还就是steps(1),单数!

可是单数怎么能带s呢?于是乎就有了step-startstep-end它俩了。

3. start 和 end

有的同学可能早就按耐不住自己躁动的内心:道理我都懂,语法我也都知道,这个start和end的意思我小学也背过,但是我就是想知道start和end究竟是控制着哪方面的开始和结束!帧动画的最后一帧显示不出来到底和他俩有没有点啥关系呢?

答案是:当然有关系!

咱们正常人肯定都是这么想的:一个动画我分为了七步,假如我让动画运行七秒,那么每一秒钟就要走一步,七秒过后我应该会看见七帧。

这么想很正常对吧!听起来挺是那么回事的啊!

但实际上是大家的认知和电脑的认知不一致,所以导致了这场误会。

那么接下来我就带领大家一起揭晓一下人类和电脑互相之间都是怎么定义帧动画的:

/* 定义动画:动画名(change-color) */ 
@keyframes change-color {
    /* 第1步 */ from { color: red } /* 红 */
    /* 第2步 */ 16% { color: orange } /* 橙 */
    /* 第3步 */ 32% { color: yellow } /* 黄 */
    /* 第4步 */ 48% { color: green } /* 绿 */
    /* 第5步 */ 64% { color: cyan } /* 青 */
    /* 第6步 */ 80% { color: blue } /* 蓝 */
    /* 第7步 */ to { color: purple } /* 紫 */
}

假如我们用steps(1)来运行这个动画,那么:

人类的想法:

第一步:红色

第二步:橙色

第三步:黄色

第四步:绿色

第五步:青色

第六步:蓝色

第七步:紫色

而电脑的想法:

第一步:红色到橙色

第二步:橙色到黄色

第三步:黄色到绿色

第四步:绿色到青色

第五步:青色到蓝色

第六步:蓝色到紫色

steps()就是控制着这第一步到第二步、第N步到第N+1步。

steps(1)就代表了第一步到第二步:红色到橙色之间用一步就走完。

同理,steps(10)就代表了第一步到第二步:红色到橙色之间之间要慢慢过渡10次。

用一张图片来方便大家理解:

编程之家

图片就可以很明显看出steps()控制的到底是哪个地方。

仔细数一数,steps()是不是要比红橙黄绿青蓝紫(我们定义过的帧)少一个啊?

所以我们最后一帧才会显示不出来,那么start和end又代表的是什么含义呢?

从图中可以看出每一个steps()里面都包含了两个步骤,start和end就是控制这个的。

假如说从红到橙需要一秒钟,那么start就表示第一秒钟的开始阶段就从红变到橙色了,由于第一秒的一开始(也就相当于零秒)就红变橙了,也就是说红色还没来得及展示就变成橙色了,所以用户压根就看不见这个红色,结果就是start会丢失第一帧。

end也是同理,红色持续一秒,在第一秒的最后阶段才会变成橙色,这样的话我们就看得见红色了。然后来到第二帧,第二帧是从橙变黄。

橙色持续一秒然后在这一秒的最后阶段变黄、黄变绿、绿变青、青变蓝、然后就来到了最后一帧:蓝变紫。

蓝色在本次动画的最后一秒一开始就持续一秒,然后紫色在最后一秒的最后阶段才会出现,但是到了最后一秒得最后阶段就意味着本次动画即将结束了,紫色也是刚出现就即将消失,所以用户也看不见紫色,结局就是end会丢失最后一帧。

这里附上一张w3c的step工作原理图:

编程之家


steps(1, end) 那张图来举例:假如第一步是从红到黄,那么图中的实心小圆点代表了红色,然后圆点后面的线段代表红色持续的时间,空心小圆点代表该变成黄色但还没变成黄色,直到下一个实心小圆点才会变成黄色,依此类推。

从这张图的走势就可以很好的看出startend的各自丢帧情况,start的第一帧是空心的,end的最后一帧虽然是实心的,但后面已经没有了线段,也就是代表最后一帧没有任何的运行时间,所以它们分别会丢失第一帧和最后一帧。

3. 小结

我知道这很难理解,毕竟人类脑子里面想的都是这种方式:

编程之家

而计算机确是这么运行的:

编程之家

所以在本篇的一开始我才会让大家先记住结论,防止大家看不懂就不想继续往下看了。

在前面也说了解决方案,大家有时间的可以来试一试,有利于更进一步的去理解这段令人费解的内容。