做爲一名真正的前端開發者,咱們不能只關注前端邏輯部分。畢竟「水銀泄地」般的頁面設計和「炫酷逼真」的動畫效果,是咱們區別於其餘程序員所特有的優點之一。javascript
儘可能百分之百的還原視覺稿,爲UE設計靈感和用戶視覺享受架起一座橋樑:正所謂「晉帝時祭北郊,更祝版,工人削之,筆入木三分。」
借古書法形容咱們的代碼,當真是恰當準確又自戀無比。html
以前的一些文章大多都是分享JS相關內容。今天輕鬆一下,我來談談前端頁面的動畫部分。經過剖析一個「跑男」動畫實例,來把CSS3中動畫相關的知識點抽絲剝繭,一網打盡。若是讀者有本身的感想或者不同的看法,歡迎一塊兒討論。前端
整個項目的Github地址能夠參考這裏。對比線上效果,這個倉庫進行了90%的刪減,可是更加適合練手和理解。感興趣的讀者歡迎拉下來本身玩一玩。裏面只有一關動畫,您能夠比葫蘆畫瓢進行調試練習。java
這是一個運營活動頁面——"春季馬拉松大比拼":用戶以闖關形式參加,並進行角色扮演。在知足必定條件下,本身扮演的馬拉松選手會繞着跑道(非正規跑道形狀)前進,向終點發起衝擊。git
部分頁面動畫效果以下:程序員
固然,這個動畫並不完美。考慮到時間性價比,我只用了兩幀重複循環模擬擺腿動做。但也達到了運營和產品小妹的需求。若是在沒有上線壓力的狀況下,咱們徹底能夠拆分更多幀,把他打磨的更流暢順滑。github
首先,咱們來看一下它的具體實現方式吧。面試
這一系列的動畫設計,出於性能和簡單的考慮,我採用了純CSS3來實現。CSS3實現動畫,主要有兩種方式:transition屬性和animation屬性。
前者是用來「平滑的改變CSS的值」。通常對於須要特定幀處理的動畫,顯然是蒼白無力的,這裏就不過多介紹了。重點介紹一下animation屬性。app
animation屬性實際上是一個簡寫屬性,就像咱們更加熟悉的「background」同樣。它用於設置六個動畫屬性:函數
1)animation-name
2)animation-duration
3)animation-timing-function
4)animation-delay
5)animation-iteration-count
6)animation-direction
最重要的就是animation-name,它規定了須要綁定的keyframes名稱。keyframes,咱們用來定義幾個關鍵節點幀。
具體我不會進行科普。若是初學者不瞭解,社區上關於這些的資料但是一大把。
回到具體的業務場景,咱們進行分析。跑男的動畫其實能夠拆分爲兩個:
1)一個是交替擺腿;
2)另外一個是位置移動。
這兩個動做要嚴絲合縫的結合。能把這個想清楚,那就基本思路理解了。
接着,如何讓這兩種動畫一塊兒施加在「靜止的」跑男身上呢?
我採用了增長一個div標籤,做爲父節點包裹的方式:
<div class="man-wrapper" id="man-wrapper">
<div class="man" id="man"></div>
</div>複製代碼
'man-wrapper'這個div與'man'這個div尺寸大小徹底一致,視覺上絕對重合。父節點處理位移,子節點負責交替擺腿:
.man-wrapper {
display: inline-block;
width: 46px;
height: 75px;
position: absolute;
}
.man {
display: inline-block;
width: 46px;
height: 75px;
background: url(img/sprite.png);
position: absolute;
top: 0;
left: 0;
}複製代碼
當須要觸發位移,開啓跑步狀態時,父節點添"start-run"類:
$('.man-wrapper').addClass('start-run');複製代碼
同時,子節點添加"running"類:
$('#man').addClass('running');複製代碼
關於「start-run」位移的動畫設計,在跑道上直道部分相對簡單,咱們思路是使用transform:translate3d。
可是視覺稿上存在很多於5處不規則彎道,在不改變原圖的基礎上,以及在不增長多餘圖片的原則下,咱們可使用transform:rotate3d,使跑男進行側身。具體設計看下圖:
1)1-2和4-5,只須要改變transform:translate3d;
2)2-4部分,即2,3,4這三個階段是爲了彎道準備的。固然,若是時間充足,咱們徹底能夠拆分的更加細緻,更加細分。
3)其中3是彎道中心的45度轉身:rotate3d(0,0,1,45deg);
4)其中4是已經徹底轉身:rotate3d(0,0,1,90deg);
具體代碼:
.start-run {
animation: start-run 5000ms;
animation-fill-mode: forwards;
animation-timing-function: linear; } @keyframes start-run {
0% {
transform: translate3d(0, 0, 0);
}
35% {
transform: translate3d(0, 155px, 0) rotate3d(0, 0, 1, 0deg);
}
50% {
transform: translate3d(20px, 224px, 0) rotate3d(0, 0, 1, -45deg);
}
70% {
transform: translate3d(80px, 242px, 0) rotate3d(0, 0, 1, -90deg);
}
100% {
transform: translate3d(200px, 243px, 0) rotate3d(0, 0, 1, -90deg);
}
}複製代碼
爲何是35%,50%,70%呢?這個是我調試出來,相對能達到順暢效果。若是追求更嚴謹的話,徹底能夠列一個極座標計算一下位移和時間。固然這樣子成本會比較大。
還有一點值得一提的是animation-timing-function: linear; 通常馬拉松中段,都近似於勻速跑吧~
解決完了位移的問題,咱們來看擺腿動做。這個其實就是兩張圖片在交替播放。就是gif圖原理。我使用了改變background-position,來切換精靈圖片的方式處理:
.running {
animation: running-man 1200ms steps(2) infinite;
}
@keyframes running-man {
0% {
background-position: 0 0;
}
50% {
background-position: 92px 0;
}
}複製代碼
千萬不要掃一眼代碼完事兒,這裏還有一些最重要的細節要注意。首先是「infinite」的使用,這個應該沒什麼意外吧。另外,你可曾注意了steps這個函數?
咱們知道animation定義的關鍵幀之間是「平滑過渡」的。這個平滑過渡怎麼理解呢?我作了一個「反例」示圖來講明。
在使用keyframes改變雪碧圖background-position時,獲得效果:
這樣的"平滑過分"顯然不是咱們想要的。
因此,在切換雪碧圖背景的方案下,steps()就要派上用場了。順便說一句,最近面試一些人,提到熟悉CSS3動畫,可是大部分都還不知道這個steps階躍函數。若是你還不清楚,能夠參考這裏。
藉助steps()函數,咱們實現了交替跑動的分解動畫:
作到這裏,其實尚未徹底結束。有一些值得咱們思考的問題。
1)真的有必要多一個標籤,來相互結合生成動畫嗎?
其實不是的,animation很神奇很強大的一點在於:它能夠接受多個動畫屬性序列。好比上邊那種狀況咱們徹底能夠這樣實現:
.running {
animation: start-run 5000ms forwards linear, running-man 1200ms steps(2) infinite
}複製代碼
2) 若是刻意追求更佳完美的動畫,咱們還須要哪些儲備?
不得不要說數學和物理知識了。好比,二次方曲線、三次方曲線、一直到五次方曲線,正弦餘弦、圓弧、拋物線、反彈曲線、彈簧曲線等等。若是你對研究這些有興趣,這裏安利一些:高性能動畫實現以及可視化1,可視化2。
除了數學公式之外,也須要咱們掌握樣式預處理器函數使用。畢竟,那麼多幀咱們不可能本身手動實現。
流暢高效的動畫,絕非一朝一夕就能完成,須要各方面甚至跨領域的積累。若是你對此很感興趣,歡迎討論。
最後,這篇文章中截圖部分採用了我廠UE:許冬設計師的視覺稿,和PM:田小甜大小姐的交互設計。
PS:百度知識搜索部大前端繼續招兵買馬,有意向者火速聯繫。。。