如今 CSS 3 动画已经非常常见,网上关于 CSS 3 动画的介绍也不少,但大多数都没提及 steps() 这个函数。最近在制作 miss.cat 的 loading 动画时,尝试了一下该函数,发现还蛮实用的。

什么是动画

当然这里要说的不是详细表述怎样称为「动画」,而是要先弄清楚一个概念:在 CSS 3 中哪部分是一个动画的过程。我们先来看一段代码:

@keyframes loading {
    from { background-position-x: 0px; }
    to { background-position-x: -3000px; }
}

这是一段很简单的代码,在这段代码中 from { ... } 指的是动画起始时的样式,很明显 to { ... } 就是结束时的样式。这里起始时的样式是背景偏移为 0 像素,结束时背景 X 轴偏移值为 -3000 像素。

@keyframes loading {
    0% { background-position-x: 0px; }
    50% { background-position-x: -1500px; }
    100% { background-position-x: -3000px; }
}

这段代码实现了一个相同的动画过程,只不过它分为 3 个阶段去描述了这个动画过程的不同样式。所以简单的说 @keyframes 是定义了一个完整动画过程,在不同状态时的不同样式。弄清楚了什么是动画的过程,才能更好的去理解如何控制动画的播放方式。

动画时间的控制

有了动画的过程,就要说一下控制动画播放时间的 animation-timing-function 属性,这个属性的默认值为 ease 也就是常见的慢进慢出,除此之外还有 linear 等,每一种速度模式都有直观的贝塞尔曲线可以表达。

而其实 steps() 也是 animation-timing-function 属性的其中一种值,没错,这个属性既然叫 function 其实它是指一个函数,包括 easelinear 其实都是内置函数的名称,只是 steps() 的效果有那么点与众不同。

为什么说 steps() 比较与众不同呢,因为上面说的几种动画时间的模式,都是具有连贯性的,要么平均速度、要么有快有慢,而我们这里要说的 steps() 是一种「步进式」的、不连贯播放的动画,用一个逼格高一点的词来说它叫做「阶跃函数」。

说到这里,应该能够大概清楚动画过程、与动画速度之间的关系了。比如我们第一段中的 keyframes 动画,如果使用 linear 那么背景偏移是一个平均速度的渐变过程,而如果使用 steps() 函数的话,则会变成一帧一帧的步进过程。

现在来看看 steps() 函数,这个函数有 2 个参数:

  • 第一个参数为整数,必填,表示将整个动画过程划分为多少帧;
  • 第二个参数为 startend,选填,表示第一帧为动画开始或结束的状态,默认为 end

使用场景

有时候遇到一个比较复杂的动画效果,比如一个小人在跑动,那么是不适合全部用 CSS 绘制出来的。往往这时候就会使用 GIF 等动态图片直接应用。但是 GIF 动态图片除了体积较大、还存在 256 色的问题。这个时候我们就可以用上 steps() 函数来代替传统的 GIF 图片了。

比如上面的这张 GIF 动态图,仅仅有 10 帧却要 222 KB 大,这在网页中是相对「不划算」的。如果我们把 10 帧动画拆分出来:

像这样我们把 10 帧画面排列在一张图片上,并保存为更现代化的 PNG 格式,体积缩小到 112 KB 直接降低了一倍。现在我们就来看看如何把一张横排的图片,用 CSS 3 动画让它动起来:

#animation {
    background: url(background.png);
    width: 300px;
    height: 300px;
    animation: animation 1s steps(10) infinite;
}

@keyframes animation {
    from { background-position-x: 0px; }
    to { background-position-x: -3000px; }
}

非常简单的一段代码,我们不需要在 @keyframes 指定每一帧的画面坐标,只需要定义好起始和结束两个状态,然后用 steps(10) 去拆分为 10 帧步进,就可以实现跟 GIF 一样的效果了,并且如果要修改动画的速度也非常方便,直接改 CSS 就好。

后记

一直以来我都想写一篇关于 CSS 3 动画的博客,所以这一次顺便把动画的一些概念介绍了一下,导致篇幅较长,但理解起来更有帮助。

至于 steps() 这种步进式的动画,应用的场景远远不仅是代替 GIF 而已,如果配合 SVG 甚至可以做出矢量的动画,这将远远超越 GIF 的可用场景。而关于上面 GIF 图片体积的问题,当然也是与色彩优化等问题有关的,这里就不展开细说了。

由于目前浏览器支持的问题,可能还需要一段时间才会更加普及 steps() 这种玩法,好在移动端的浏览器目前基本没问题,做一些微信小游戏啥的,就可以用上咯。

标签: CSS