《 CSS Secrets 》是 @Lea Verou 最新著作,这本书讲解了有关于CSS中一些小秘密。是一本CSSer值得一读的一本书,经过一段时间的阅读,我、@南北和@彦子一起将在W3cplus发布一系列相关的读后感,与大家一起分享。
通常,我们需要一个动画效果是比较难的或者说使用CSS的 transition 是不可能实现的。例如,一个卡通移动或一个复杂的进度条。在这种情况下,基于图像的逐帧动画是完美的,但是实现这种效果是具有挑战性的。
在这一点上,你可能会说:难道我们不能使用gif动画?很多情况下,答案是肯定的,gif动画是完美的。然而,他们也有一些缺点,可能在一些地方无法使用:
上图是一个半透明的进度指示器( dabblet.com ),这个是Gif图无法实现的效果。
早在2004年,Mozilla团队就解决了前两个问题,他们通过逐帧动画PNG文件,实现类似静态的方式或者动画的GIF文件。他们把这种设计称为 APNG 。但是,直到今天,支持APNG的浏览器和制图软件都非常有限。
开发人员甚至通过使用一个Sprite图和使用JavaScript脚本来动态更改 background-position 值,在浏览器中实现灵活的逐帧动画。你甚至可以找到一个小的库来完成,那么有没有一个简单的方法,使用CSS来实现这样的效果呢?
假设我们所有帧动画用到的Sprites的PNG图如下所示:
我们有一个元素,用来制作加载动画(别忘了,在元素里面放些文本,提搞可访性!),元素大小是单帧动画的尺寸:
<div class="loader">Loading...</div>.loader { width: 100px; height: 100px; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); text-indent: 999px; overflow: hidden; background: url(http://www.w3cplus.com/sites/default/files/blogs/2015/1507/loader.png) 0 0;}
目前结果如下图所示:
将显示的是第一帧,但是没有动画效果。如果我们对 background-position 进行不同值的设置,比如 -100px,0 是第二帧, -200px 0 是第三帧等等。这样一来,首先想到的他可能是一个动画:
@keyframes loader { to { background-position: -800px 0; }}.loader { animation: loader 1s infinite linear; /*省略其他样式*/}
然而,正如下图所看到的图片(每 167ms ),这并不是真正需要的效果:
当我们不需要关键帧之间的插值时,我们最初尝试的逐帧动画效果失败了。
虽然我们还没有实现逐帧动画效果,但实际上我们已经非常接近解决方案。这里有一个秘密,将使用 steps() 时间函数来替代前面介绍的“Bézier-based”时间函数。
你可能会问,这是什么时间函数?正如上一节介绍的,我们看到的都是有关于“Bézier-based”时间函数来控制关键帧之间的平滑过渡。通常情况之下,在 transition 和 animation 都可以实现平滑过渡。然而,在这种情况这下,这种平滑过渡时间函数直接摧毁了我们使用Sprite制作的动画。
steps() 时间函数和“Bézier-based”很不一样,他可以根据整个动画的关键帧步骤指定步骤的数量,并且可以对插值进行开关的设置。在CSS中,有关于 steps() 讨论不太多。至于CSS中有关于时间函数功能,“Bézier-based”才是亲妈的生,很受欢迎,但 steps() 是后妈的,一直不受人待。然而,在这种情况下, steps() 才正是我们需要的。一旦把这个用到加载的动画中,动画才变得正常,也是我们需要的效果:
animation: loader 1s infinite steps(8);
请记住, steps() 还可以接受第二个参数,而且这个参数是可选的。 start 或 end (默认的),用来设定每个时间间隔开关,如下图所示:
如果我们只需要一个步骤,也可以通过 step-start 和 step-end 快捷键,其相当于 steps(1,start) 和 steps(1,end) 。
提示: Simurai 给Sprites动画提供了一个使用 steps() 技术 。