今天,有在群裡看到這樣一個問題:有一個動畫,一開始靜止處於第一幀,只在使用者 hover 的時候執行動畫,在執行一次後停止,並且停留在最後一幀,使用 CSS 可以完成麼?
像是這樣:
一個非常有意思的問題,答案是可以的。我們抽取一下其中的關鍵點:
首先,動畫只執行一次,未執行前處於第一幀,執行完後處於最後一幀。
這個剛好利用 CSS 動畫的 animation-fill-mode: both
即可。
animation-fill-mode: backwards
:可以讓元素在動畫開始之前的樣式為動畫執行時的第一幀,動畫結束後的樣式則恢復為 CSS 規則設定的樣式animation-fill-mode: forwards
:元素在動畫開始之前的樣式為 CSS 規則設定的樣式,而動畫結束後的樣式則表現為由執行期間遇到的最後一個關鍵幀計算值(也就是停在最後一幀)而,animation-fill-mode: both
兼顧了上面兩種模式的特點,可以使得動畫開始前的樣式為動畫執行時的第一幀,動畫結束後停在最後一幀。
而動畫通過 hover 驅動,只有使用者 hover 元素的時候,動畫才進行這一點,利用 animation-play-state
即可。
我們都知道,正常情況下,動畫應該是執行狀態,那如果我們將動畫的預設狀態設定為暫停,只有當滑鼠點選或者 hover 的時候,才設定其 animation-play-state: running
,這樣就可以利用 hover 控制動畫的行進!
基於上述兩點,我們來實現一個有意思的打字動畫,做到動畫只觸發單次,並且只有 hover 的時候動畫會執行。
<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;
}
}
預設情況下,展示這樣一個介面:
接下來,我們把滑鼠放上去,看看會發生什麼:
有意思,完美的實現了上面說的要求 -- 動畫通過 hover 驅動,只有使用者 hover 元素的時候,動畫才進行。
當然,這裡還運用了幾個小技巧,一併解釋下:
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 步的逐幀動畫,這裡的元素剛好和程式碼中的一一對應上藉助上面 4 步及搭配我們上文介紹的 animation-fill-mode: both
、animation-play-state: paused
的應用,我們就完美的實現了這樣一個非常有意思的打字動畫。
完整的程式碼,你可以戳這裡 CodePen Demo -- running once animation by hover
如果你想對 CSS 動畫有更深入細緻的瞭解,可以翻看我的這篇文章,對動畫的每一個屬性都有著十分細緻的講解:深入淺出 CSS 動畫
OK,本文到此結束,希望本文對你有所幫助