在本系列的前两篇文章中我们分别对transition和animation动画有了基础的了解,这两种动画基本都是基于某种“属性参数变化”的动画。而当我们需要制作一些通过属性变化无法实现的动画效果时,就需要使用逐帧动画。在本篇教程中我们将介绍简单的逐帧动画做法,通过制作一段简单的跑步动画来演示HTML5中以图片序列来实现逐帧动画效果的方法。
逐帧图片绘制
首先,在Illustrator之类的矢量绘图软件中绘制好跑步动作的每一个环节。
创建逐帧动画时,最方便的是使得每一帧的动画都有着相同的大小,我们可以在PhotoShop中完成这一尺寸调整。在此我们将每一帧的内容都设置为300*372像素的宽高。
将以上图像存为PNG图片,命名为run.png。现在,逐帧图片就制作完成了。
由于其中包含了12帧动画,每一帧为300*372像素,则该run.png文件尺寸为3600*372像素。
CSS样式制作
接下来,我们回到HTML文件,为跑步动画准备一个DOM容器,代码如下:
<div class="run"></div>
然后,设置run类的CSS样式,将run.png作为背景,且不重复平铺,设定好容器的宽度和高度,使得在该大小范围内正好能够显示出一帧动画。代码如下:
.run {
width: 300px;
height: 372px;
background: url(run.png) no-repeat;
}
测试页面,现在我们只能看到第一帧的动画内容。
添加animation动画
逐帧动画的基本思路就是通过移动背景图片的位置,来实现图片的切换,进而呈现出动画效果。由于我们的动画一共有12帧,加上动画开头和结尾是同样的两个节点,因此一共需要有13个节点,将100%平均分为13份,则可以得到每个节点的百分比值依次为0%、8.3%、16.7%...100%。在每个节点中,我们只需设置background-position属性,使图片依次向左移动300像素即可。代码如下:
@keyframes run {
0%, 100% {
background-position:0 0;
}
8.3% {
background-position:-300px 0;
}
16.7% {
background-position:-600px 0;
}
25% {
background-position:-900px 0;
}
33.3% {
background-position:-1200px 0;
}
41.7% {
background-position:-1500px 0;
}
50% {
background-position:-1800px 0;
}
58.3% {
background-position:-2100px 0;
}
66.7% {
background-position:-2400px 0;
}
75% {
background-position:-2700px 0;
}
83.3% {
background-position:-3000px 0;
}
91.7% {
background-position:-3300px 0;
}
}
为了精简篇幅,以上代码中我们略去了-webkit-的兼容性写法。接下来,我们为run类设置animation属性,将动画时长设置为900毫秒,并无限循环,代码如下:
.run {
-webkit-animation: run 900ms infinite;
animation: run 900ms infinite;
}
测试页面,我们并没有得到预想中的逐帧动画效果,而是背景图片一直向右快速移动的效果。
让动画平滑起来
我们也很容易理解这一效果的产生原因,animation默认背景图片位置在水平方向上发生了位移,因此整个动画过程是以平滑的形式呈现的。我们要使其“一格一格”地显示,则可以使用animation动画的steps方法,使得每一个动画关键帧都以“台阶”而非“线性”的形式显示,代码如下:
.run {
-webkit-animation: run 900ms steps(1) infinite;
animation: run 900ms steps(1) infinite;
}
现在再次测试页面,我们就能够看到流畅的逐帧动画了。
逐帧的另一种制作思路
除以上的背景位置切换方式外,我们也可以用多张图片交替呈现的方式制作逐帧动画。
首先,我们要将每一帧单独保存为一个文件,在此可以使用PhotoShop中的切片工具来快速完成该操作。
当完成切片后,我们可以将图片以HTML和图像的形式保存,PhotoShop会自动生成单张且序列化命名的图片文件。
接下来,我们要准备12个div元素,每个div元素用于放置一张图片,其id属性名依次为frame1至frame12,代码如下:
<div class="run">
<div id="frame1" class="run-pic"></div>
<div id="frame2" class="run-pic"></div>
...
<div id="frame11" class="run-pic"></div>
<div id="frame12" class="run-pic"></div>
</div>
接着,使每一个div都以绝对定位的方式显示在run容器的左上角,并为这些div分别设置背景图片。
.run {
width:300px;
height:372px;
position:relative;
}
.run-pic{
position:absolute;
width:300px;
height:372px;
display:block;
top:0;
left:0;
}
#frame1{
background:url(images/run_01.png);
}
#frame2{
background:url(images/run_02.png);
}
/*省略其它代码*/
#frame12{
background:url(images/run_12.png);
}
最后,我们使用jQuery来实现动画效果。我们的制作思路是首先将12张图片全部隐藏,然后将第一张图片显示,停留0.1秒后隐藏,第二张图片则延迟0.1秒显示,刚好接上第一张图片隐藏,第三张图片延迟0.2秒,以此类推。所有12张图片全部显示完毕后,第一张图片再次显示,因此两次动画轮回间需要延迟的时间是其余11张图片的显示时间,即1.1秒。我们可以创建一个loop函数供反复调用,以生成这一动画轮回,而在动画最开始时,则需要通过遍历div元素,为每个元素设置初始的延迟值。代码如下:
<script type="text/javascript">
$(document).ready(function() {
$('.run-pic').each(function(index){
$(this).hide(0).delay(index*100).show(0,loop);
});
});
function loop(){
$(this).delay(100).hide(0).delay(1100).show(0,loop);
}
</script>
在以上代码中,每张图片都立即调用hide(0)方法,马上隐藏起来,继而通过delay()方法实现延迟,延迟的时间等于索引值乘以100,因此第一张图片延迟0毫秒,第二张图片延迟100毫秒,第三张图片延迟200毫秒...在经过了延迟时间后,该图片再通过调用show()方法来显示,此时也调用了loop函数,使图片开始进入动画的轮回。测试页面,我们将得到与之前的CSS动画完全相同的逐帧动画效果。
小结
与CSS动画相比,使用JavaScript创建逐帧动画有利也有弊,其弊端是制作过程更加复杂一些,其有利之处在于它对动画的控制能力更强,同时能够呈现更加复杂的动画效果。在实战开发中我们应该根据实际情况灵活地选择动画的实现方式。
此外,除以上两种方式外,我们还可以使用Canvas画布来绘制逐帧动画,在后续文章中将详细介绍具体实现方法。
本例源文件://cloud.ecnu.edu.cn/p/DUDncGwQGRjDAw
THE END
via://zhuanlan.zhihu.com/p/27141575