譯者注:這篇文章比較古老了,大概成文於2011年。放在當今急速變化的web前端世界中似乎有些不合時宜。不過究其所寫的內容-CSS動畫的原理,則萬變不離其宗,理解動畫的基本原理非常重要,裡面提到的12條基礎動畫原則,對建立高質量的動畫效果有著極好的指導意義。當時支援CSS動畫屬性的瀏覽器很少,如今幾乎所有主流瀏覽器基本都支援了(別跟我提IE哦)。文章中的程式碼示例和我們今天寫的CSS3動畫基本是一致,放在現在的瀏覽器跑也沒有相容性問題。
現如今 Firefox 和 基於Webkit引擎的瀏覽器都支援CSS動畫了,擇日不如撞日,何不嘗試一下。拋去技術形態,不管是傳統動畫、電腦3D動畫、Flash或CSS,遵循的動畫原理都是相通的。
我們將在文章中初步瞭解CSS動畫,並按照指導原則建立CSS動畫。然後將通過例項,使用傳統動畫原理建立CSS動畫。最後,展示一些真實世界裡的用例。
CSS 動畫屬性
在深入之前,我們先寫點基礎的CSS:
Animation 是CSS的新屬性,允許我們不需要藉助Javascript或Flash就能為HTML元素(如:div、h1 和 span)建立動畫。現在支援這個屬性的瀏覽器有 包含Webkit 引擎的瀏覽器,如:Safari 4+、Safari for iOS (iOS 2+)、Chrome 1+和Firefox 5。 不支援該屬性的瀏覽器則會忽略動畫程式碼,此時要確保你的頁面不完全依賴這個屬性。
由於這個技術相對來說較新,需要新增瀏覽器廠商的字首。到目前為止,每個瀏覽器的語法規則都是一樣,只是用字首區分。下面的程式碼例子中,我們用的是 -webkit 字首語法。
要為元素新增動畫,你只需要將CSS 動畫關聯到該元素就可以了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* This is the animation code. */ @-webkit-keyframes example { from { transform: scale(2.0); } to { transform: scale(1.0); } } /* This is the element that we apply the animation to. */ div { -webkit-animation-name: example; -webkit-animation-duration: 1s; -webkit-animation-timing-function: ease; /* ease is the default */ -webkit-animation-delay: 1s; /* 0 is the default */ -webkit-animation-iteration-count: 2; /* 1 is the default */ -webkit-animation-direction: alternate; /* normal is the default */ } |
首先,我們建立動畫程式碼。這段程式碼可以出現在CSS檔案中的任何位置,只要元素能找到相應動畫的名字(animation-name)就可以了。
還有一種更簡便的方法為元素新增動畫:
1 2 3 |
div { -webkit-animation: example 1s ease 1s 2 alternate; } |
這段程式碼做了一定簡化,並沒有把所有屬性值都寫上。如果某些值沒有寫,瀏覽器會回退使用預設值。
這些是最基礎的。下面我們將展示更多的程式碼。
使用傳統動畫原理
在我看來,傳統動畫的鼻祖迪斯尼,早期在著名的圖書《Illusion of Life》裡創立了傳統動畫的12條原則。這些基礎原則可以應用到所有型別動畫,不過你並不需要像動畫專家一樣遵循。我們將這12條原則運用到CSS動畫例項上,把一個基礎動畫轉變成更加可信的視覺幻象。
雖然只是蹦蹦跳跳的小球,但你可以看出兩個版本中的不同世界。
這個例子展示了CSS動畫特性。下面的程式碼中,我們用一些空div元素來展示如何運作;我們都知道這程式碼不夠語義化,但重點在於它將頁面變得生動起來,這在以前的瀏覽器中是絕對做不到的。
擠壓和拉伸
這個彈跳球為壓扁和拉伸做了很好的展示。如果彈球高速下落並撞擊地面,你可以觀察到它被擠扁然後在彈回的過程中被拉伸。
在基本常識層面,這個例子讓我們的動畫有了重量和伸縮的感覺。如果扔一個保齡球,我們不會期待它有任何拉伸,很可能只是會撞壞地面。
可以通過CSS3的屬性 transform 來產生壓扁和拉伸的效果。
1 2 3 4 5 |
@-webkit-keyframes example { 0% { -webkit-transform: scaleY(1.0); } 50% { -webkit-transform: scaleY(1.2); } 100% { -webkit-transform: scaleY(1.0); } } |
這段程式碼會將物體縱向(y軸,上下)的比例改變為原始比例的1.2倍,然後回覆到原始尺寸。
我們還為這個動畫使用了稍微複雜一點的定時器。對於基礎動畫只需要起始(from)和結束(to)就可以了。但你也可以通過白分比的方式為每個時間點設定動畫,就像程式碼所展示的那樣。
擠壓效果已經實現了。現在我們利用轉換(translate)來移動物體。我們可以它將形變放在一起。
1 2 3 |
50% { -webkit-transform: translateY(-300px) scaleY(1.2); } |
轉換屬性允許我們在不改變基礎屬性(如 位置、寬度、高度)的前提下操作物體,這就使其非常適合CSS動畫。這個特別的轉換屬性讓小球在動畫的中間點從地面彈起。
(請注意:要檢視這個動畫,你需要最新版的Firefox、Chrome或Safari。筆者書寫這段文字的時候,Safari瀏覽器提供了最佳視覺體驗。)
(譯者注:現如今主流的瀏覽器都已經能很好的實現動畫效果了)
沒錯,小球看起來還是很糙,不過這個小小的調整是讓動畫變得逼真的第一步。
預備
預備在主要動作發生之前增加了懸念或力量感。舉個例子,在你起跳之前腿部的彎曲有助於觀察者預判你下一步會做什麼。在我們的彈球例子中,事前增加一個簡單的影子表示有東西將要從上面掉下。
我們新增了另一個 div 元素代表影子,這樣我們可以單獨的為其設定動畫。
要在這裡增加預期,我們需要讓小球快速掉入場景中。通過適配各百分比的時間點來實現,小球在開始點和第一個動作之間沒有移動。
1 2 3 4 5 6 7 8 |
@-webkit-keyframes example { 0% { -webkit-transform: translateY(-300px) scaleY(1.2); } 35% { -webkit-transform: translateY(-300px) scaleY(1.2); } /* Same position as 0% */ 65% { -webkit-transform: translateY(0px) scaleY(1.2); } /* Starts moving after 35% to this position */ 67% { -webkit-transform: translateY(10px) scaleY(0.8); } 85% { -webkit-transform: translateY(-100px) scaleY(1.2); } 100% { -webkit-transform: translateY(0px); } } |
在動畫的35%的時間點前,小球在場景中的位置沒有發生變化,沒有移動。然後在 35% 到 65%,小球忽然出現在舞臺上,剩下的動畫緊接著跟上。
也可以使用動畫延遲(animation-delay)來實現預備:
1 2 3 |
div { -webkit-animation-delay: 1s; } |
舞臺
現在試試把舞臺新增到場景中,將動畫放入環境中。回顧一下迪士尼的電影,如果去掉了奇妙的背景會變成什麼樣?這是魔法的半壁江山。
舞臺也是吸引注意的關鍵元素。與劇院的舞臺一樣,光線總是照射到最重要的區域。舞臺應該加入到視野中。除了彈球,我為彈球的降落新增了一個簡單的背景。這樣看客就知道舞臺的中央會出現動畫,場景也就可以從一片大白雪(白色區域)中脫穎而出了。
逐幀 VS 狀態到狀態
在傳統動畫中,可以選擇如何構成自己的動畫。逐幀意味著需要畫出序列的每一幀。狀態到狀態意味著建立序列的少數關鍵幀,然後填充中間的間隔。填充間隔在被稱作漸變(“in-betweening”或“tweening”),這是製作Flash動畫的術語。
在CSS動畫中,我們通常使用第二種方式,狀態到狀態。就是說,我們將為動作新增關鍵幀,之後瀏覽器將會自動在這些關鍵幀直接做漸變平滑處理。當然,我們同樣也能向逐幀技術學習。瀏覽器只提供有限的動畫效果;有時候,你為達到某種的效果時,必須採用更困難的方式為多種動畫做拼接。
慣性和重疊
和物理世界一樣!慣性和重疊常用在人物的身體移動中,例如人物胳膊的搖擺或頭髮的下落。想象一個人頂著大肚腩快速的轉身:他們的身體先轉過來,然後肚腩迅速跟上。
對我們來說,這意味著當球掉落時需要使其符合物理定律。上面的例子中小球掉落很不自然,就跟沒有受到重力的影響一樣。我們希望小球掉落,然後彈起。不過得講完下一原則才能實現。
慢進慢出
這是與加速或減速有關。想象一個超速的汽車需要停下來。如果它瞬間就停下來,肯定沒人信。我們知道汽車需要時間來減速,所以要先讓汽車剎車並緩慢停止。
還有一個和重力相關的效果。想象兒童盪鞦韆。當他們達到最高點時會減速,當返回到最低點時又會加速。最快的速度出現在弧面的底部。然後上升到相反的方向,如此反覆。
回到我們的例子,調整進和出的速度可以讓小球的運動(最終)更加可信。
當球撞擊地面,碰撞會使起迅速彈回。當抵達最高點,它會減速。這樣看起來小球像是真正的掉落。
在 CSS 中,我們可以控制 animation-timing-function 屬性:
1 |
-webkit-animation-timing-function: ease-out; |
這些屬性包含以下這些值:
- ease-in 開始時緩慢,然後加速。
- ease-out 開始時快速,然後減速直到停止。
- ease-in-out 開始緩慢,一直加速到中段,然後減速直到停止。
- linear 一直保持勻速。
你還可以使用貝塞爾曲線來建立自定義的緩動速度。
弧線
與遵循物理定律類似,弧線遵循的基本原則叫做“上升的東西必然落下”。弧線在思考物體運動軌跡時非常有用。
這個動畫用 CSS 來實現稍微繁瑣一點。我們想讓小球上下運動的同時往邊上移動。所以,我們讓小球從左邊平滑進入的同時保持彈跳動畫。與其把所有的動作都放到一個動畫中,不如做兩個獨立的動畫更簡單。在這個例子裡,我們將小球用另一個 div 元素包裹,然後單獨新增動畫。
HTML
1 2 3 |
<div class="ball-arc"> <div class="ball"></div> </div> |
CSS
1 2 3 4 5 6 7 8 9 10 11 |
.ball-arc { -webkit-animation: ball-x 2.5s cubic-bezier(0, 0, 0.35, 1); } /* cubic-bezier here is to adjust the animation-timing speed. This example makes the ball take longer to slow down. */ /* 這的貝塞爾曲線用作調整動畫的速度。 這個例子使小球的減速時間更長了*/ @-webkit-keyframes ball-x { 0% { -webkit-transform: translateX(-275px); } 100% { -webkit-transform: translateX(0px); } } |
這樣,我們通過一個動畫移動小球的側方向(ball-x),另一個動畫控制小球的彈跳(ball-y)。 這個方法唯一不好的地方在於,如果你想做的事情很複雜,最終會讓你陷入一堆缺乏語義的程式碼堆砌之中。
輔助動畫
輔助動畫是讓動畫顯得更加真實的微妙之處。輔助動畫致力於細節。打個比方,如果有一個留著長髮的人行走,主動作是行走,輔助動作是頭髮的擺動,或者也可能是衣服的褶皺隨風變化。
我們的例子和這個非常相似。為了增加小球的更多細節,我們製作小球紋理的輔助動畫。這樣就造成了小球是被扔進來的錯覺。
這次不再為這個動畫新增另一個div元素,我們新增一個 img 影像元素充當小球的紋理。
1 2 3 4 5 6 7 8 |
.ball img { -webkit-animation: spin 2.5s; } @-webkit-keyframes spin { 0% { -webkit-transform: rotate(-180deg); } 100% { -webkit-transform: rotate(360deg); } } |
定時
這條原則只針對動畫定時。如果動畫的定時控制得越好,就越接近真實世界。
小球的例子完美的闡釋了這個觀點。例子中的小球很輕,設定這個速度合適的。如果是一個保齡球,我們會希望它下落的速度更快。而如果動畫比現在更慢,則看起來像是在太空中打網球。選擇合適的時間點會讓你的動畫看起來更真實。
可以很方便地通過 animation-duration 來調整時長,也可以通過動畫的百分比設定單獨的時長。
誇張
卡通片以誇張或難以置信的物理特性著稱。一個卡通人物可以變形成任何形狀然後在恢復正常。在很多應用場景中,通過誇張來突出,讓動畫富有活力。否則看起來會很平淡。
儘管如此,使用誇張效果時需要謹慎。迪士尼有一個符合現實原則的方法,但稍微推進了一步。想象一個角色朝牆裡跑,它的身體會被壓扁的特別誇張,用來強調碰撞的力量。
我們使用擠壓和拉伸的誇張手法讓小球對地面的撞擊更加明顯。我還為動畫新增了更精緻的搖晃。最後,我們在球的彈跳過程中拉伸小球來突出速度感。
就像之前新增動畫的做法一樣,我們再新增一個 div 元素,這個元素使小球撞擊地面時同時產生搖晃。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
@-webkit-keyframes wobble { 0%, 24%, 54%, 74%, 86%, 96%, 100% { -webkit-transform: scaleX(1.0); /* Make the ball a normal size at these points */ } 25%, 55%, 75% { -webkit-transform: scaleX(1.3) scaleY(0.8) translateY(10px); /* Points hitting the floor: squash effect */ } 30%, 60%, 80% { -webkit-transform: scaleX(0.8) scaleY(1.2); /* Wobble inwards after hitting the floor */ } 75%, 87% { -webkit-transform: scaleX(1.2); /* Subtler squash for the last few bounces */ } 97% -webkit-transform: scaleX(1.1); /* Even subtler squash for last bounce */ } } |
這段程式碼看起來比之前複雜了不少。這是簡單的試錯。在找到合適的效果錢需要反覆嘗試。
紮實繪圖及角色魅力
能夠教你就這麼多了……至少在程式碼方面。最後這兩條動畫原則無法通過程式碼來體現。他們是你日後需要完善的技能,使你最終能製作真正迷人的動畫。
當迪士尼開始製作白雪公主的動畫時,他們的動畫師被派回去重新學習寫生和人體結構。這種對細節的關注在影片中可見一斑。這正好說明良好的動畫需要紮實的繪畫功底和聲樂知識。
大多數的CSS動畫和錯綜複雜的數字動畫不大相同,但是基礎原則是一致的。無論是透過正在開啟的門顯示內容,還是正在密封併傳送一封“聯絡我們”的信封,動畫都必須是可信的,不能像機器一樣……除非你製作的就是機器動畫。
每一個動畫角色都有獨特的魅力。就像迪士尼總給我們展示的,任何事物都可以有性格:一個茶壺、一棵樹、甚至是勺子。但在CSS的世界裡,需要考慮整體動畫如何有助於設計,使整體的體驗更令人滿意。我們不想在此製作大眼怪的動畫。
奔跑吧動畫!
CSS的動畫特性非常棒。和每一個CSS新特性一樣,一開始容易被過度使用和錯誤的使用。甚至有點會重蹈Flash複雜動畫頁面覆轍的危險。儘管我有信心Web社群應該不會這麼做。
CSS動畫能讓網站變得有生機。也許我們的小球動畫不夠簡潔,但它向我們展示一種利用CSS讓頁面上任何元素變鮮活的可能。
CSS動畫還可以讓頁面上的元素更容易互動,讓頁面更有意思。結合JavaScript,甚至能成為製作遊戲動畫的另一條路。將上面的12條原則應用在你的動畫中,能使你的網站更有信服力、更誘人、更有趣,從而帶來更好的完整體驗。
譯者推薦:
如果你和我一樣懶,想製作CSS動畫又不想寫複雜的CSS3程式碼,這有兩個非常不錯的CSS3開源動畫庫推薦給你,Animate.css和CSS3 ANIMATION CHEAT SHEET。另外譯者也編寫了一個CSS3動畫製作庫H5Show,讓你輕鬆的建立時下流行的Html5演示動畫。當然想製作出高水準的動畫,理解文章中的12條動畫原則非常重要。