CSS 揭秘(8)--逐帧动画

Posted by liveipool on February 9, 2017

逐帧动画

43.1.png
如果我们想要实现上面这种加载提示的donga,基于图片的逐帧动画才是最完美的选择。
不使用GIF是因为GIF所能使用的颜色数量最多为256色,GIF不具备Alpha透明的特性,GIF无法操控持续时间,循环次数,是否暂停等等,相当不方便。

2004年,Mozilla发起了一个建议,在PNG格式中增加对逐帧动画的支持,就像GIF格式同时支持静态图像和动画一样。这种格式被称为APNG。不过至今只有Chrome支持APNG。

那么我们应该如何通过CSS实现这种逐帧动画呢?

我们首先将所有帧都拼合到一张PNG图片中:
43.2.png

然后用一个元素来容纳这个加载提示,并把它的宽高设置为单帧的尺寸:

<div class="loader">Loading...</div>

.loader {
	width: 100px;
	height: 100px;
	background: url(img/loader.png) 0 0;
	/*把文本隐藏起来*/
	text-indent: 200%;    /*首行缩进父元素宽度的两倍*/
	white-space: nowrap;  /*不允许换行,这样总共就只有一行*/
	overflow: hidden;  /*把超出长度的隐藏掉*/
}

接下来,如果我们尝试着去对它应用各种不同的background-position值,会发现它的图片会是平稳过渡的,实现不了我们帧动画的效果:
43.3.png

这是因为,在这里我们不能再使用基于贝塞尔曲线的调速函数,而需要采用steps()这个调数函数。基于贝塞尔曲线的调数函数的平滑的过渡确实是我们使用CSS过渡和动画的原因。但在眼前的情景下,这种平滑特性恰恰毁掉了我们想实现的逐帧动画效果。
与贝塞尔曲线调数函数迥然不同的是,steps()会根据你指定的步进数量,把整个动画切分为多帧,而且整个动画会在帧与帧之间硬切。
最后完整的代码:

@keyframes loader {
	to { background-position: -800px 0; }
}

.loader {
	width: 100px;
	height: 100px;
	/*把文本隐藏起来*/
	text-indent: 200%;    /*首行缩进父元素宽度的两倍*/
	white-space: nowrap;  /*不允许换行,这样总共就只有一行*/
	overflow: hidden;  /*把超出长度的隐藏掉*/
	background: url(http://dabblet.com/img/loader.png) 0 0;
	animation: loader 1s infinite steps(8);
}

steps()还接受可选的地热各参数,其值可以是start或end(默认值),这个参数用于指定动画在每个循环周期的什么位置发生帧的切换动作。如果我们只需要一个单步切换效果,还可以使用step-start和step-end这样的简写属性,它们分别等同于steps(1,start)和steps(1,end)。