歡迎關注微信公眾號: 前端偵探
介紹一個 CSS 動畫合成小技巧。先看效果
這是一個非常“動感”的倒數計時效果,通常在一些活動開場中比較常見,分析一下整個動畫過程,不難發現,有以下幾類動畫
- 數字的變化
- 縮小和放大
- 透明度變化
不知道小夥伴能否觀察出來呢?下面來一起來看看具體實現吧
一、數字的變化
先來看數字的變化。
這個技巧在之前的文章:還在使用定時器嗎?CSS 也能實現電子時鐘 中首次用到,這裡再次介紹一下
在以前,數字的變化可能需要建立多個標籤,然後改變位移來實現
<count-down>
<span>5</span>
<span>4</span>
<span>3</span>
<span>2</span>
<span>1</span>
</count-down>
這種方式需要建立多個標籤,略微繁瑣,也不易擴充套件。現在有更簡潔的方式可以實現了,那就是 CSS @property。這是幹什麼的呢?簡單來講,可以自定義屬性,在這個例子中,可以讓數字像顏色一樣進行過渡和動畫,可能不太懂,直接看例子吧
假設 HTML 是這樣的
<count-down style="--t: 5"></count-down>
然後我們通過 CSS 變數將數字渲染到頁面,這裡需要藉助偽元素和計數器
有興趣的可以參考這篇文章:小tips: 如何藉助content屬性顯示CSS var變數值
count-down::after{
counter-reset: time var(--t);
content: counter(time);
}
效果如下
如何讓這個數字變化呢?可以用到 CSS 動畫
@keyframes count {
to {
--t: 0
}
}
count-down::after{
--t: 5;
counter-reset: time var(--t);
content: counter(time);
animation: count 5s forwards;
}
效果如下
現在的效果僅僅是5秒後,數字從 5 變成了 0,並沒有 5 => 4 => 3 => 2 => 1 這種階段變化。然後最重要的一步來了,加上以下自定義屬性
@property --t {
syntax: '<integer>';
inherits: false;
initial-value: 0;
}
對的,僅僅新增這一小段 CSS,效果就出來了
是不是很神奇?可以這麼理解,通過@property
定義後,這個變數--t
本身可以單獨設定動畫了,就像顏色變化一樣。
另外,使用計數器的好處是可以隨意更換型別,比如將上面的阿拉伯數字換成中文計數,只需要更換計數器型別就行了
完整型別可以參考:list-style-type
count-down::after{
--t: 5;
counter-reset: time var(--t);
content: counter(time, cjk-decimal); /*中日韓十進位制數*/
animation: count 5s forwards;
}
效果如下
是不是非常方便呢?
二、倒數計時的終點
上面的計數器最後的終點是“0”,顯然我們需要一些特定的提示,比如“Go~”
如何改變最後一幀的狀態呢?這裡有兩種方式:
- 通過動畫覆蓋
- 通過計數器覆蓋
首先來看第一種方式,這個比較好理解,重新定義一個動畫,在倒數計時結束後,將最後一幀重置一下
@keyframes stop {
to {
content: 'Go~';
}
}
count-down::after{
--t: 5;
counter-reset: time var(--t);
content: counter(time);
animation: count 5s forwards,
stop 5s step-end forwards;
}
·效果如下
注意這裡動畫函式是step-end
,為啥是這個呢?step-end
也可寫作steps(1,end)
,你可以理解為在整個動畫只有兩種狀態,在執行過程中,都是初始狀態,只有到達最後一幀才改變狀態,下面是 MDN 的截圖
下面來看第二種方式,通過自定義計數器來實現。原理其實和 JS 思維有些類似,當數字為 0 時,讓計數器指定一個特殊的值,具體實現如下
@counter-style stop {
system: cyclic;
symbols: "Go~";
range: 0 0;
}
這裡簡單解釋一下,這裡有個range
屬性,表示計數器的範圍,由於這裡只需要指定為 0,所以是區間0 0
。然後是system
,表示計算系統,這裡為cyclic
,表示迴圈使用開發者提供的一套字元,字元由symbos
定義。然後symbos
表示計算符號,也就是具體展示的字元,這裡指定為Go~
就行了。
這部分自定義計數器內容比較複雜,也比較新,有興趣的可以參考張鑫旭的這篇文章:CSS @counter-style規則詳細介紹
然後是應用
count-down::after{
/**/
counter-reset: time var(--t);
content: counter(time, stop); /*自定義計數器*/
}
這樣也能達到相同的效果,實現也更加優雅
三、縮放和透明度變化
這兩個動畫其實是同時進行的,可以放在一個動畫裡
@keyframes shark {
0%{
opacity: 1;
transform: scale(1);
}
50%{
opacity: 0;
transform: scale(0.4);
}
}
然後設定動畫時長為 1s,迴圈 5 次
count-down::after{
--t: 5;
counter-reset: time var(--t);
content: counter(time);
animation: count 5s steps(5) forwards,
shark 1s 5;
}
效果如下
是不是稍微有些突兀?因為數字的變化是突然的,需要將數字的變化隱藏到透明度為 0 的時候,為了達到這種效果,只需要將閃爍動畫延遲 0.5 秒即可
count-down::after{
--t: 5;
counter-reset: time var(--t);
content: counter(time);
animation: count 5s steps(5) forwards,
shark 1s .5s 5; /*延遲 0.5s*/
}
這樣就自然多了
不過還有優化的空間。比如現在數字動畫有些太連貫了,如果希望數字出現後稍微停留一小會,或者說希望出現的慢一點,消失的快一點,如何處理呢?其實這比想象中的要容易許多,只需要改一下關鍵幀位置就行了,如下
@keyframes shark {
0%{
opacity: 1;
transform: scale(1);
}
20%{
opacity: 0;
transform: scale(0.4);
}
}
同時,延遲的時間也需要改成 0.8 秒,效果如下
這樣就實現了文章開頭所示效果
下面重點來了~完整程式碼如下
@property --t {
syntax: '<integer>';
inherits: false;
initial-value: 0;
}
@counter-style stop {
system: cyclic;
symbols: "Go~";
range: infinite 0;
}
html,body{
margin: 0;
height: 100%;
display: grid;
place-content: center;
}
count-down{
display: flex;
align-items: center;
justify-content: center;
font-family: Consolas, Monaco, monospace;
font-size: 120px;
}
count-down::after{
--t: 5;
--dur: 1;
counter-reset: time var(--t);
content: counter(time, stop);
animation: count calc( var(--t) * var(--dur) * 1s ) steps(var(--t)) forwards,
shark calc(var(--dur) * 1s) calc(var(--dur) * .8s) calc(var(--t));
}
@keyframes count {
to {
--t: 0;
}
}
@keyframes shark {
0%{
opacity: 1;
transform: scale(1);
}
20%{
opacity: 0;
transform: scale(0.4);
}
}
你也可以訪問線上例子:CSS count-down(codepen.io)或者CSS count-down(juejin.cn)
另外,demo 中還有個小彩蛋,點選可以重新執行動畫,實現方式如下
count-down:active::after{
animation: none;
}
四、其他動畫效果
除了縮放效果,還可以有一些位移的動畫,比如這樣的
@keyframes shark {
0%{
opacity: 1;
transform: translateY(0);
}
20%{
opacity: 0;
transform: translateY(100px);
}
}
效果如下
是不是有點奇怪?動畫不夠連貫,一會向下一會向上,有沒有辦法消失和出現都是從上到下的呢?當然也是可以的,實現如下
@keyframes shark {
0%{
opacity: 1;
transform: translateY(0);
}
20%{
opacity: 0;
transform: translateY(100px);
}
21%{
opacity: 0;
transform: translateY(-100px);
}
}
這裡多加了一個非常“鄰近”的關鍵幀,表示在透明狀態下,“迅速”改變位移,這樣在數字出現時的動畫就感覺是從上到下的,整體更為流暢,效果如下
還可以調整一下前面的縮放效果,讓出來的時候更大,效果也更為震撼
@keyframes shark {
0%{
opacity: 1;
transform: scale(1);
}
20%{
opacity: 0;
transform: scale(.4);
}
21%{
opacity: 0;
transform: scale(5);
}
}
效果如下
當然還有其他效果,比如旋轉,斜切等,這就需要發揮你的想象了~
五、總結和說明
以上就是本文的全部內容了,一個簡單的小動畫,你學會了嗎?下面總結一下實現要點:
- 複雜動畫可以分解成多個簡單的動畫
- 數字的變化可以通過多個標籤,改變位移實現
- CSS 計數器可以將數字變數渲染到頁面
- CSS @property 以將CSS變數設定動畫,就像顏色變化一樣
- CSS 計數器的好處是可以隨意更改型別,比如中文計數
- 倒數計時的終點預設是數字 0 ,可以通過另一個動畫重置最後一幀
- 可以通過自定義 CSS 計數器,讓某個計數符號渲染成指定字元
- 縮放和透明的變化是同時進行的,可以放在一個動畫裡
- 數字的變化需要注意安排在透明度為0的時候,不然數字變化很突兀
- 數字的出現和消失動畫可以新增一個鄰近的關鍵幀來快速歸位
文中用了一些比較新的屬性,比如 @property,還有自定義計數器,不過沒關係,文中也都提到了其他解決方案,動畫的整體思路是不變的,如何觀察和分解動畫,這個才是最重要的。最後,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉發❤❤❤
歡迎關注微信公眾號: 前端偵探