Skip to content

在前面的 transition-timing-function 和 animation-timing-function 这两个属性中,不仅可以填入一个三次贝赛尔曲线,还可以填入一个叫做 step 的东西,从英文可以看出,这个 step 有阶梯的意思,确实是这样,不管是贝赛尔曲线还是 step 本质上都可以用一个 st 图来表示,贝赛尔曲线就是一个光滑曲线,而 step 就是一个阶跃函数,或者形象地说是阶梯函数。读者可以这样理解,timing-function 这个东西本身就是一个函数,传入的都是一个 st 函数,也就是位移随着时间变化的变化函数。

这里介绍 step 使用 animation 来介绍,transition 同理。

css
@keyframes changeColor {
            0% {
                background-color: red;
            }
            50% {
                background-color: green;
            }
            100% {
                background-color: blue;
            }
        }

定义上述动画,实际效果如下:

144

由于 animation-timing-function 的默认值为 ease,即缓入缓出的一个贝赛尔曲线,如果我修改为 linear,则会变成如下线性变换:

221

这两个效果显而易见地不同,可以看到,不管是 linear 还是 ease,都是贝赛尔曲线,而贝赛尔曲线在 st 图像上都表现为光滑的曲线,所以它过渡得很连贯。我这里使用 steps 函数来生成一个阶梯函数,steps(1, end),看一下效果。

208

我们可以看到,它就是一卡一卡地动,或者说一帧一帧地动,所以其实我们可以很直观地理解这个函数。首先,我们的一切动画都是由一帧一帧的静态图像构成的,比如屏幕上之所以能展示连贯的动画,本质上就是因为屏幕一秒钟可以播放 60 张图片,人眼就会把这快速播放的 60 张图片脑补成一个连贯的动画,但其本质还是每秒快速播放的 60 张图片。

这里蓝色不见了,在后面会解释

而我们使用贝塞尔曲线的时候,其实就在两个关键帧之间根据贝赛尔曲线自动补出了很多中间帧,但如果我不希望它补出那么多的中间帧,就可以使用 steps 函数生成的阶梯函数来实现,steps 函数第一个参数是每两个关键帧之间进行几次状态变化,最小就是 1 次吧,因为从 1 个关键帧变化到另一个关键帧至少要经过 1 次状态变化,如果我要让每两个关键帧之间进行两次状态变化,就填入 2,这个时候 CSS 为了实现我这个效果,就会在两个关键帧中间加上一个中间帧。

244

很明显,这里的棕色就是 CSS 给我补充的中间帧。

如果我设置为 10,那么每两个关键帧中间都会经过 10 次状态变化,CSS 就会在中间生成 9 个关键帧。

248

此时每两个关键帧中间就产生了 9 个中间帧,CSS 让这些帧快速切换就实现了以上效果,这看起来已经像是一个连贯的动画了,但这本质上还是一系列静态图片的快速切换。

可以这样思考,当 steps 函数第一个参数达到某个值的时候,其效果可以达到和原先动画一样的效果,但 steps 函数并不是用来干这个事的。

也就是说,以前的动画都是在两个关键帧中间补出非常多的中间帧,中间帧的快速切换完成了这个动画效果,但我现在并不希望它过渡得那么平滑,比如我只希望它在两个关键帧中间补出 2 个中间帧,也就是说每两个关键帧中间经过三次状态改变,那我将 steps 的第一个参数设置为 3 即可。所以 steps 本质上就是一步一步跳跃式地走,而不是像以前动画那样平滑的过渡。

接下来是 steps 的第二个参数,第二个参数要么写 end,要么写 start。end 表示保留当前帧的状态直到动画结束,start 表示保持下一帧的状态,直到动画结束。

css
@keyframes changeColor {
            0% {
                background-color: red;
            }
            50% {
                background-color: green;
            }
            100% {
                background-color: blue;
            }
        }

还是这个动画,我们看到,0% 和 50% 是两个关键帧,例如我将 steps 的第一个参数写成 1,就会直接从 0% 变到 50%,但是在这个过程中只能显示一种颜色吧,到底显示 0% 的样式还是显示 50% 的样式就是一个问题,这个问题就是通过第二个参数来决定的。

例如我将第一个参数设置为 2,那么在 0% 和 50% 中间会添加一个中间帧,那在 0% 到这个中间帧的过程中,样式是固定的,如果填 end,那么就会用 0% 的样式,如果写 start,用的就是这个补出来的中间帧的样式。

这里我就可以解释为什么最开始蓝色消失的问题了,当时设置的是 steps(1,end),也就是每两个状态之间变化一次,并且保持初始状态直到最后。从 0% 到 50% 保持的是红色,而从 50% 到 100% 保持的是绿色,但 100% 这一个点会立刻变到蓝色,但只有这一刻,接下来立刻就变成红色了,所以这一帧我们是很难用肉眼捕捉得到的。

我们可以用 animation-fill-mode 中的 forwards 来弥补这里一帧的缺失,这个值可以让动画结束之后保持最后一帧的状态。

一般情况下我们使用 end 就足够,除非是一些特殊需求,我们可以认为 start 就是最开始就变化, end 表示时间到才变化。

注:steps(1,end) 相当于 step-end,steps(1,start) 相当于 step-start

这个 steps 的应用有很多,只要是一跳一跳地这种动画,都可以用这个 steps 来实现,比如打字机效果就是一个字一个字打出来的,比如钟表效果就是一格一格跳动的,也可以用来实现逐帧动画。

以下是练习源码:step练习.zip

以笔记为镜,可以知得失