妙啊!动画还可以这样控制?
共 3433字,需浏览 7分钟
·
2022-05-28 17:47
作者:chokcoco
来源:SegmentFault 思否社区
今天,有在群里看到这样一个问题:有一个动画,一开始静止处于第一帧,只在用户 hover 的时候运行动画,在运行一次后停止,并且停留在最后一帧,使用 CSS 可以完成么?
像是这样:
一个非常有意思的问题,答案是可以的。我们抽取一下其中的关键点:
动画只运行一次,未运行前处于第一帧,运行完后处于最后一帧 动画通过 hover 驱动,只有用户 hover 元素的时候,动画才进行
animation-fill-mode 控制元素在各个阶段的状态
首先,动画只运行一次,未运行前处于第一帧,运行完后处于最后一帧。
animation-fill-mode: backwards:可以让元素在动画开始之前的样式为动画运行时的第一帧,动画结束后的样式则恢复为 CSS 规则设定的样式
animation-fill-mode: forwards:元素在动画开始之前的样式为 CSS 规则设定的样式,而动画结束后的样式则表现为由执行期间遇到的最后一个关键帧计算值(也就是停在最后一帧)
反向利用 animation-play-state 实现 hover 触发动画行进
而动画通过 hover 驱动,只有用户 hover 元素的时候,动画才进行这一点,利用 animation-play-state 即可。
<p>Hover Me - You are a pig!</p>
p {
position: relative;
font-family: monospace;
width: 26ch;
animation: typing 3s steps(15, end);
animation-fill-mode: both;
animation-play-state: paused;
overflow: hidden;
}
p:hover {
animation-play-state: running;
}
p::before {
position: absolute;
content: "";
width: 4px;
top: 0;
bottom: 0;
right: 0;
animation: blink .8s linear infinite;
}
@keyframes blink {
0%, 50% {
border-right: 4px solid transparent;
}
50%, 100% {
border-right: 4px solid #000;
}
}
@keyframes typing {
from {
width: 11ch;
}
to {
width: 26ch;
}
}
打字动画运用了逐帧动画,而不是补间动画,主要利用了 CSS 动画的 step-timing-function 步骤缓动函数,也就是代码中的 steps(15, end)
ch 是 CSS 当中的一个相对单位,这一单位代表元素所用字体 font 中 “0” 这一字形的宽度
font-family: monospace 表示等宽字体,每个字符占据的宽度是一样,因为我们使用了 26ch 来充当 <p> 元素的宽度,而 Hover Me - You are a pig 这一段文字算上空格刚好 26 个字符,26ch 刚好表示这一段文本的长度
一开始展示的文本 Hover me - 算上空格是 11ch 宽度,而最后整个文本展示完需要 26ch 的宽度,中间需要经过 15 步的逐帧动画,这里的元素刚好和代码中的一一对应上