妙??!動(dòng)畫還可以這樣控制?
作者:chokcoco
來源:SegmentFault 思否社區(qū)
今天,有在群里看到這樣一個(gè)問題:有一個(gè)動(dòng)畫,一開始靜止處于第一幀,只在用戶 hover 的時(shí)候運(yùn)行動(dòng)畫,在運(yùn)行一次后停止,并且停留在最后一幀,使用 CSS 可以完成么?
像是這樣:

一個(gè)非常有意思的問題,答案是可以的。我們抽取一下其中的關(guān)鍵點(diǎn):
動(dòng)畫只運(yùn)行一次,未運(yùn)行前處于第一幀,運(yùn)行完后處于最后一幀 動(dòng)畫通過 hover 驅(qū)動(dòng),只有用戶 hover 元素的時(shí)候,動(dòng)畫才進(jìn)行
animation-fill-mode 控制元素在各個(gè)階段的狀態(tài)
首先,動(dòng)畫只運(yùn)行一次,未運(yùn)行前處于第一幀,運(yùn)行完后處于最后一幀。
animation-fill-mode: backwards:可以讓元素在動(dòng)畫開始之前的樣式為動(dòng)畫運(yùn)行時(shí)的第一幀,動(dòng)畫結(jié)束后的樣式則恢復(fù)為 CSS 規(guī)則設(shè)定的樣式
animation-fill-mode: forwards:元素在動(dòng)畫開始之前的樣式為 CSS 規(guī)則設(shè)定的樣式,而動(dòng)畫結(jié)束后的樣式則表現(xiàn)為由執(zhí)行期間遇到的最后一個(gè)關(guān)鍵幀計(jì)算值(也就是停在最后一幀)
反向利用 animation-play-state 實(shí)現(xiàn) hover 觸發(fā)動(dòng)畫行進(jìn)
而動(dòng)畫通過 hover 驅(qū)動(dòng),只有用戶 hover 元素的時(shí)候,動(dòng)畫才進(jìn)行這一點(diǎn),利用 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;
}
}


打字動(dòng)畫運(yùn)用了逐幀動(dòng)畫,而不是補(bǔ)間動(dòng)畫,主要利用了 CSS 動(dòng)畫的 step-timing-function 步驟緩動(dòng)函數(shù),也就是代碼中的 steps(15, end)
ch 是 CSS 當(dāng)中的一個(gè)相對(duì)單位,這一單位代表元素所用字體 font 中 “0” 這一字形的寬度
font-family: monospace 表示等寬字體,每個(gè)字符占據(jù)的寬度是一樣,因?yàn)槲覀兪褂昧?nbsp;26ch 來充當(dāng) <p> 元素的寬度,而 Hover Me - You are a pig 這一段文字算上空格剛好 26 個(gè)字符,26ch 剛好表示這一段文本的長(zhǎng)度
一開始展示的文本 Hover me - 算上空格是 11ch 寬度,而最后整個(gè)文本展示完需要 26ch 的寬度,中間需要經(jīng)過 15 步的逐幀動(dòng)畫,這里的元素剛好和代碼中的一一對(duì)應(yīng)上
最后

