利用CSS3的animation step屬性實現wifi動畫(結尾有彩蛋)

泱泱發表於2017-07-28

之前攢的滿滿的SVG+CSS3做動畫的技能一直未能放個大招,理由很簡單,因為本身從事行業的性質,軟體裡不能出現勞什子動畫這等花裡胡哨的東西,哦,不不,叫隱喻行為引導的趣味化。用canvas實現了一個科技感滿滿的動態繪製背景的登入頁面,因為渲染佔了20M記憶體,20M啊筒子們,那就是將近1個G啊,然後,就沒有然後了,誰讓客戶的機器還有1G記憶體的呢。至於唯一被使用的loading圖示,no,no,no,前端只用預設的,懶得改。最近在做的一個軟體有個刷卡的介面,就需要有一枚圖示來表示開啟“刷卡監聽”狀態,機會來了,終於有了實踐的機會,什麼?你說靜態圖片就可以?不不,動態表達的含義更明確,就這麼愉快的決定了。

動畫拆解
動畫拆解

因為只是一個wifi圖示,所以本身也簡單的很,動畫效果不過就是1→1+1→1+1+1→1+1→1這種迴圈,GIF來做簡單到沒朋友,三幀迴圈播放,隨隨便便搞個軟體都能實現,即使UI小白,大概看了這種圖示也會很輕蔑的不屑一顧的走開吧。
咳咳,那我們用SVG來實現吼不吼?

##1.動靜分離
這裡又要祭出我們的“動靜分離大法”了,靜態元素就是最下面的圈圈咯。然後動態元素就是上面那兩條槓槓咯。
先借助AI導三部分的路徑出來。

<path id="top" d=""/> <!--頂部槓槓-->
<path id="middle"  d=""/><!--中間槓槓-->
<path d=""/><!--底部圈圈-->複製程式碼

##2.定義基礎的動畫
這種一閃一閃的動畫,第一時間想到的就是通過定義關鍵幀的透明度的改變來實現,不過這裡透明度opacity是兩個極值,0對應消失,1對應出現,那先把基礎的動畫寫出來。先對時間軸進行拆分,以確定關鍵幀的時間點。

時間軸拆解
時間軸拆解

如上圖,關鍵幀時間確定之後,可以著手定義CSS樣式了。

<style>
@keyframes top{
0%{opacity:0}
30%{opacity:1}
70%{opacity:0}
}
@keyframes middle{
0%{opacity:0}
15%{opacity:1}
85%{opacity:0}
}
path{fill:#32b16c}
#top{animation:top 1s infinite}
#middle{animation:middle 1s infinite}
</style>複製程式碼

此時得到的動態SVG是下面這種

漸變的wifi動畫
漸變的wifi動畫

完全不是我們想要的效果~~
因為animation會自動形成過渡效果的,類似做動畫時的補間,那麼問題來了,我們要的可是無過渡的幀動畫效果,不是這枚變淡變深的貨,go on 繼續,你離成功只差一個屬性值了。

##3.steps引數的定義
先碎碎念一遍animation所有的屬性值,animation-name|動畫名稱,animation-duration|一個週期的時間,animation-timing-function|動畫速度曲線,animation-delay|動畫延遲開始的時間,animation-iteration-count|動畫播放次數,animation-direction|動畫是否下一週期逆向播放,animation-play-state|動畫執行狀態,animation-fill-mode|動畫時間外物件的狀態。
我們在實際定義動畫時,當然不會這麼一一的去寫屬性名稱,而是直接寫屬性值。碼了這麼多字,是想說學習要知其然更要知其所以然,即使最後會放出可以複用的程式碼,但能看明白,然後自己去改去做豈不妙哉。
steps引數對應的是animation-timing-function|動畫速度曲線,我們最常用的就是預設的線性,或者稍微自然的ease,這裡偏偏反行道而行之,steps()指定了兩個引數,一個為整數值,表示跳幀動畫間隔數量,第二個為start和end,預設為end,表示這種跳幀動畫是在間隔的起點還是終點變化。
當然了,對於我們這個動畫而言,跳幀間隔是1,所以我設定steps(1),對應動畫設定變成下面這種:

#top{animation:top 1s steps(1) infinite}
#middle{animation:middle 1s steps(1) infinite}複製程式碼

那動畫效果呢,看一下:

跳幀動畫效果wifi
跳幀動畫效果wifi

就是這種效果!
這裡簡單說一下,為什麼不能設定成steps(1,start),如果讓跳幀動畫在間隔的起點變化,以中間形狀middle為例,在0%→15%的間隔中,我們設想中是在15%的時間點發生透明度opacity變成1的跳幀動畫,也就是時間間隔的終點,如果改成起點,就意味著在0%的時間點透明度就變成1了,同理,15%→85%的時間段,在這個時間段的起點15%時就發生了透明度opacity變成0的跳幀動畫。
動畫時間軸就變成了下面介個樣子

動畫時間軸拆解
動畫時間軸拆解

動畫效果放一下,可以對比一下:

修改steps引數後的跳幀動畫
修改steps引數後的跳幀動畫

很明顯,中間形狀出現的時間很短,得到了正好相反的效果(該出現時消失,該消失時出現)。
我們順便對上面的程式碼優化一下:當我把時間軸一分為二,會發現是左右對稱的

左右對稱的時間軸
左右對稱的時間軸

那可以通過定義逆向播放屬性值alternate,然後精簡關鍵幀,記得同時動畫週期的時間也要相對縮短1/2,得到程式碼及註釋如下:

<svg>
<style>
@keyframes top{
0%{opacity:0}
30%{opacity:1}
}
@keyframes middle{
0%{opacity:0}
15%{opacity:1}
}
path{fill:#32b16c} <!--如果要設定三種不同顏色,在#top和#middle裡面單獨定義一個fill值-->
#top{animation:top 0.5s steps(1) alternate infinite}
#middle{animation:middle 0.5s steps(1)  alternate infinite}
</style>
<path id="top" d=""/>
<path id="middle"  d=""/>
<path  d=""/>
</svg>複製程式碼

著迷於SVG的原因就在於,可以隨隨便便替換個顏色,比如下面這種:

三種不同顏色的wifi圖示
三種不同顏色的wifi圖示

##4.附贈steps延伸動畫
說好的結尾彩蛋來了!
當然了,把steps屬性用在我們這個SVG動畫案例裡著實是大材小用了,“噠噠噠”,能想起什麼,沒錯!時鐘!用steps屬性實現的跳幀動畫來做個鬧鐘的指標動畫效果,這還差不多嘛。
先隨隨便便來一個鬧鐘如下:

時鐘基礎圖形
時鐘基礎圖形

來,跟我再念一遍,“動靜分離大法”,拆成下面兩個部分,記得AI裡面分在不同圖層,搞好命名,別把自己弄暈了。

靜態圖形
靜態圖形

指標層
指標層

匯出的SVG我把程式碼簡化一下如下:

<g id="base">
……此處為若干鬧鐘底層形狀的組成程式碼……
</g>
<path d=""/><!--時針對應的路徑-->
 <path d=""/><!--分針對應的路徑-->複製程式碼

好了,現在這個鬧鐘裡面有兩個指標,就定義為時針hour和分針minute吧,下面就要給這兩個指標定義旋轉動畫了。我們都知道,分針轉一圈360度,時針才轉30度(1/12)。也就是說,在定義動畫週期時,hour對應的時間應該是minute的12倍。比如,我讓分針旋轉一圈的時間為3s,那對應時針則是36s,既然是要實現跳幀動畫,記得加上steps屬性。動畫的CSS屬性如下

<style>
@keyframes hour{
0%{transform:rotate(0)}
100%{transform:rotate(360deg)}
}
@keyframes minute{
0%{transform:rotate(0)}
100%{transform:rotate(360deg)}
}
#hour{animation:hour 36s steps(12)   infinite; transform-origin: }/*這裡一定要定義旋轉動畫的中心點*/
#minute{animation:minute 3s steps(12) infinite;transform-origin:}
</style>複製程式碼

看一下動畫效果如何:

時鐘動畫
時鐘動畫

嗯,噠噠噠的效果出來了,但是感覺怪怪的有沒有?問題出在哪裡呢?想想我們日常生活中,這種跳幀效果的只有秒針對不對?時針和分針都是均勻轉速。然後我們畢竟是示範動畫嘛,又不是真要做一個鬧鐘出來,為了得到好一點的效果,現在我讓指標變換一下身份,長的作為秒針,然後模擬一下我們真實的環境,1s走一步,然後短的作為分針,那就需要改一下動畫裡面的屬性了。

#minute{animation:minute 60s steps(60) infinite;}複製程式碼

秒針設定如上,動畫週期為60s,steps(60)表示60個跳幀動畫。
分針既然是順滑的旋轉,那就去掉steps屬性,那分針轉一圈是60分鐘,所以動畫週期就是3600s咯。

#hour{animation:hour 3600s infinite;  }複製程式碼

我隨意擷取了一段動畫看看效果:

秒動畫
秒動畫

當然啦,勤勞的小夥伴可以把秒針,時針,分針都加上,然後我這種急性子讓時間跑得快快的,就得到了下面這個動畫:

加速
加速

有沒有種白駒過隙感慨逝水流年的憂桑?
我的動畫設定如下:

#hour{animation:hour 7200s infinite;}  /*時針動畫設定*/
#minute{animation:minute 600s steps(60) infinite;}/*分針動畫設定*/
#second{animation:second 10s steps(60) infinite;} /*秒針動畫設定*/複製程式碼

總之,關於時間週期的關係好好理一下,比如時針轉一圈是12個小時,所以是分針的12倍,分針是秒針的60倍。另外這裡如果秒針一圈的動畫時間給的太短,就看不出跳幀效果啦~
好了,關於steps的延伸動畫到此為止~有好的應用再更新。

相關文章