去年我們發(fā)布了 Gyroscope 以來(lái),互動(dòng)許多人問(wèn)過(guò)我們做動(dòng)畫(huà)用的制作什么 JavaScript 庫,我們ヽ(′ー`)ノ也曾想過(guò)將它公布于眾,原則但實(shí)際上那并不是互動(dòng)奧妙所(′?ω?`)在。
我們不想讓大伙兒覺(jué)得自己需要依賴(lài)特別黑魔法的制作 JavaScript 插件才能解決問(wèn)題。大部分時(shí)候,原則我們都只要對最新的互動(dòng)瀏覽器和 GPU 的性能和 css3 加以利用就夠了。
其實(shí)并沒(méi)有什么絢麗動(dòng)畫(huà)的制作武功秘籍,唯一??的原則辦法就是花大量時(shí)間測試和優(yōu)化。但是互動(dòng),在經(jīng)過(guò)多年??的制作試驗和瀏覽器性能??的極限考驗,我們發(fā)現了一些設計和編碼的原則原則可以有效地提升動(dòng)畫(huà)表現。這些技巧能夠使你的互動(dòng)頁(yè)面流暢,并且能夠運行在流行的制作臺式和移動(dòng)設備的瀏覽器上,最(╬ ò﹏ó)(zui)重要的原則一點(diǎn),它們還非常易于維護。
技術(shù)手段和實(shí)現方式可能因人??而異,但是通用性的原則幾乎能無(wú)所不包。
什么是動(dòng)畫(huà)?
在互聯(lián)網(wǎng)發(fā)明之前,動(dòng)畫(huà)就( ?▽?)已經(jīng)所處可見(jiàn)了,可能你需要窮盡畢生之力才能(neng)學(xué)會(huì )如何將動(dòng)畫(huà)做得絢麗輝煌。然而,在互聯(lián)網(wǎng)中實(shí)現動(dòng)畫(huà)效果自有其獨特的限制和挑戰。
為了實(shí)現流暢的 60 幀的動(dòng)畫(huà)效果,每一幀都需要在 16 毫秒內??完成渲染!時(shí)間很短,所以我們需要找到最高效的方法去渲染每一幀內容,從ヽ(′ー`)ノ而實(shí)現流暢的表現。
一些經(jīng)典的動(dòng)畫(huà)設計原則
在網(wǎng)站上實(shí)現動(dòng)畫(huà)效果的方式多種多樣。比如??(ru),在互聯(lián)網(wǎng)出現之前隨處可見(jiàn)的電影膠片,它利用手繪的漸變的膠片,每秒鐘播放多幀來(lái)實(shí)現動(dòng)畫(huà)的錯覺(jué)。(?????)
Twitter 在最近的心形動(dòng)??畫(huà)中就利用了這種方法,通過(guò)膠片繪出一個(gè)轉動(dòng)的精靈。
這個(gè)效果也可以通過(guò)許多獨立的小元素動(dòng)畫(huà)來(lái)實(shí)現,或者用 SVG 現,但是那樣(yang)會(huì )過(guò)于復雜,并且可( ?▽?)能不會(huì )這么流暢。
許多時(shí)候,你會(huì )想要使用 CSS 切換屬性來(lái)自動(dòng)實(shí)現元素改變的動(dòng)畫(huà)效果,這種技術(shù)被稱(chēng)作“twee??ning??”—因其是在兩個(gè)不同的屬性值之間切換(譯者注:tweening 來(lái)自 transitioning be_tween_ two different values)。它的好處是可以非常簡(jiǎn)單地取消或者替換掉而不用重新構造邏輯內容,這是完美的一勞永逸式的動(dòng)畫(huà),像介紹序言等,或者如鼠標懸停等簡(jiǎn)單的交互。
更多資料: All you need to know about CSS Transitions
其他時(shí)候,基于關(guān)鍵幀的 CSS 動(dòng)畫(huà)屬性會(huì )非常適合不斷變化的背景元素。舉個(gè)例子,陀螺儀中的圓環(huán)按會(huì )照預設持續轉動(dòng),還有其他能夠利用 CSS 動(dòng)畫(huà)的(de)類(lèi)型比如齒輪。
為了免于后顧之憂(yōu),希望以下這些建議能極?大地提高你的動(dòng)畫(huà)效果:
1、除了透明度(Opacity)和切換(Traヽ(′▽?zhuān)?ノn(′?_?`)sform),不要改??變任何屬性(xing)!即??便你覺(jué)得可行,那也別沖動(dòng)!
動(dòng)畫(huà)中百分之八十的優(yōu)化會(huì )用到這項基本原則,即使是在移動(dòng)端也一樣。你或許以前聽(tīng)過(guò)這個(gè)原則,ヽ(′▽?zhuān)?ノ這不是我提出來(lái)的,但是很少有人去遵守。這跟“管住嘴邁開(kāi)腿”一樣,建議很好卻ヾ(′ω`)?也最容易被忽略。
對已經(jīng)習慣(′?_?`)了這種思路的人來(lái)說(shuō)這非常簡(jiǎn)單,但是對那些習慣用傳統的 CSS 屬性去做動(dòng)畫(huà)的人來(lái)說(shuō),這會(huì )是一次質(zhì)的飛躍。
比如,你想讓某個(gè)元素小,你可以使用 transform:scale(),而不是改變寬度;如果你想移動(dòng)它,??你可以使用簡(jiǎn)單的transform:translateX 或者 transfor??m:translateY,從而替代亂糟糟的外補白(margin)或者內補白(paddi??ng) — 那些需要重建每一幀的頁(yè)面布局。
為什么要這么做呢?
對人類(lèi)來(lái)說(shuō),改(╯°□°)╯︵ ┻━┻變寬度、外補白或者其他屬性不是什么大事 — 甚至因為簡(jiǎn)單會(huì )更讓人喜歡這么做 — 但是對電腦來(lái)說(shuō),這事兒就像天塌了一樣,甚至比這更糟糕。
瀏覽器投入了九牛二虎之力來(lái)優(yōu)化這些操(╯°□°)╯作,切換屬性(transform)真的非常容易且高效,并且??能夠充分利用顯卡,并且不用重新渲染元素。
第一(???)次加載頁(yè)面的時(shí)候,你??可能會(huì )覺(jué)得抓狂 &m(′_ゝ`)dash; 處理所有圓角、引入圖像、給一切添加陰影,如果你毫不在乎那么甚至可以再做一個(gè)動(dòng)態(tài)羽化。如果這種情況只會(huì )發(fā)生一次,多一些計算時(shí)??間也沒(méi)關(guān)系。但是一旦內容渲染完成了,ヽ(′ー`)ノ你絕對不會(huì )再想要重新加載!
更多內容: Moving elements with translate (Paul Iris(′;ω;`)h)
2、用非常清楚的方式隱藏內容,使用 Pointer-Events 屬性:僅僅利用透明度隱藏元素
或許會(huì )有跨瀏覽器的警示,但??是如果你只是面向 webkit 和其他流行的瀏覽器,它(ta)將會(huì )讓你如虎添??翼。
很(′?_?`)久以前,動(dòng)畫(huà)效果必須由 jquery 的 animate() 方法來(lái)處理,許多復雜的淡入淡出效果的處理是通過(guò) display 的屬性值切換實(shí)現的。太早顯示,那么動(dòng)畫(huà)還沒(méi)完成,但是太晚的話(huà)就會(huì )在頁(yè)面上顯示一片空白,總是需要回調函數去給執行完的動(dòng)畫(huà)擦屁股。
CSS 中的 poin(′?_?`)ter-events 屬性(xing)(盡ヽ(′ー`)ノ管已經(jīng)存在很長(cháng)時(shí)間,但是不經(jīng)常使用)只是讓元素失去了點(diǎn)擊和交互的響應,就好像它們不存在一樣。它能通過(guò) CSS 控制顯示或隱藏??,不會(huì )打斷動(dòng)畫(huà)也不會(huì )影響頁(yè)面的渲染或可見(jiàn)性。
除了將 opacity 設置為零,它和將 display 設置為 none 具有相同的效果,??但是不會(huì )觸發(fā)新的渲染機制。需要隱藏元素的時(shí)候,我會(huì )將它的 opacity 設置??為 0 并將 pointer-events 設置為 off,然后就任(ren)由其自生自滅啦。
這樣做尤其適用于絕對定位的元素,因為你能夠自信滿(mǎn)滿(mǎn)地說(shuō)他們絕對不會(huì )影響到頁(yè)面中的其他元素。
它有時(shí)也會(huì )劍走偏鋒,因為動(dòng)畫(huà)的時(shí)機并不總那么完美 — 比如一個(gè)元素在不可見(jiàn)狀態(tài)下仍然可以點(diǎn)擊ヽ(′▽?zhuān)?/或者覆蓋了其他內容,或者只有當(′?ω?`)元素淡入顯示完全的時(shí)候才可以點(diǎn)擊,但是不要灰心,會(huì )??有辦法解決的。(下文會(huì )提到解決辦法,譯者注)
3、不要一次給所有內容都設置動(dòng)畫(huà),用動(dòng)作編排加以替代
單一的動(dòng)畫(huà)會(huì )很流暢,但是和其他(′?ω?`)許多動(dòng)畫(huà)一起也許就完全亂套了。編寫(xiě)一個(gè)流暢的全員動(dòng)畫(huà)的例子很簡(jiǎn)單,但當數量級上升到整個(gè)網(wǎng)站時(shí)性能就很難維持了。因此,合理安排好每個(gè)元素非常重要。
你需要將所ヽ(′▽?zhuān)?ノ有的時(shí)間節點(diǎn)安排好,來(lái)避免所有的動(dòng)畫(huà)內容同時(shí)開(kāi)始或進(jìn)行。典型的(de)例子,2 或 3 個(gè)動(dòng)畫(huà)同時(shí)進(jìn)行可能不會(huì )出現卡慢的現象,尤其是在它們開(kāi)始的時(shí)間略有不同的情況下。但是超過(guò)這個(gè)數量,動(dòng)畫(huà)就可能發(fā)生滯緩。??
理解動(dòng)作編排這個(gè)概(╯°□°)╯念非常重要??,除非你的頁(yè)面真的只有一個(gè)元素。它貌似是舞蹈領(lǐng)域的東西,但是在動(dòng)畫(huà)界它同樣的重要。每個(gè)內容都要在(zai)合適的方向和時(shí)機出現,即使它們相互分離,但是它們要給人一種按部就班的感覺(jué)。
谷歌的 material design 有幾點(diǎn)關(guān)于動(dòng)作編排的有趣建議,雖然這并不是實(shí)現目標的不二法門(mén),但總有一些是你應該去考慮和嘗試的。
更多內容: Google Material Design · Motion
4、適當增加切換延時(shí)能夠更簡(jiǎn)單地編排動(dòng)作
動(dòng)畫(huà)的編排??非常(chang)重要,同時(shí)也會(huì )做大量的試驗和測試(′▽?zhuān)?)才能恰如其分。然而,動(dòng)畫(huà)編排的代碼并不會(huì )非常復雜。
我通常會(huì )改變一個(gè)父元素(通常是 body)的 class 值來(lái)觸發(fā)一系列的改變,這些改變有著(zhù)各不相同的切(qie)換延時(shí)以便能夠適時(shí)展現。單從代碼來(lái)看,你只需要關(guān)心狀態(tài)的變化,而不用擔心一堆時(shí)間節點(diǎn)的維持。
Gyroscope Chrome Extension 的動(dòng)畫(huà)
交錯安排一系列的元素是動(dòng)畫(huà)編排的一種簡(jiǎn)單易行的方法,這種方法很有效,因為它在性能良好的同時(shí)還好看—但請記住你本想讓幾個(gè)動(dòng)畫(huà)同時(shí)發(fā)生的。你想把這些動(dòng)畫(huà)分布開(kāi)(kai)來(lái),讓每個(gè)都表現地流暢,而不ヽ(′ー`)ノ是一下子太多動(dòng)畫(huà)從而顯得特別慢。適當部分的重疊會(huì )看起(′?_?`)來(lái)ヽ(′▽?zhuān)?/連續流暢而不是鏈式的單獨動(dòng)畫(huà)。
代碼示例
有一些很簡(jiǎn)單的技巧來(lái)錯開(kāi)你的元素—尤其是其中有非常多的內容。如果頁(yè)面中有小于 10 項內容,或者元素數量可預??估(比如靜態(tài)頁(yè)面),我通常會(huì )在 CSS 中指定特定的值。這是最簡(jiǎn)單易行的方法了。
一個(gè)簡(jiǎn)單的 SASS 循環(huán)
對更(geng)多的內(nei)容或者動(dòng)態(tài)內容來(lái)說(shuō),可以在循環(huán)中動(dòng)態(tài)地給每項內容添加時(shí)間節點(diǎn)。
一個(gè)簡(jiǎn)單的 JavaScript 循環(huán)
有兩個(gè)典型的變量:基本延時(shí)和各個(gè)項目的延時(shí)。它很難協(xié)調,但你一旦找到正確的值,效果將會(huì )非常完美。
5、在慢動(dòng)作中(zhong)使用增量設計,過(guò)后再加快動(dòng)畫(huà)的速度
動(dòng)畫(huà)設計中,時(shí)間節點(diǎn)(dian)就是一切。20% 的工作是用來(lái)實(shí)現效果,剩下的 80% 使用來(lái)尋找合適的參數和持續時(shí)間來(lái)讓一切在同時(shí)發(fā)生時(shí)顯得流暢。
尤其是在編排多個(gè)動(dòng)畫(huà)的時(shí)候,為了達到高性能和高共(gong)同性,觀(guān)察動(dòng)畫(huà)的慢動(dòng)作會(huì )讓一切工作變得非常容易。
無(wú)論你用的ヽ(′ー`)ノ是 JavaScript 還是 CSS 預處(chu)理┐(′?`)┌器比如 SASS(我們非常喜歡它),都需要簡(jiǎn)單地做一些額外的計算并且需要聲明一些有用的變量。
你必須確??保它能夠非常容易地嘗試不同的速度或(huo)時(shí)間節點(diǎn)。舉個(gè)例子,如果一個(gè)動(dòng)畫(huà)效果在 1/10 的速度下還表現地結結巴巴,那么可能會(huì )有一些非?;A的錯誤。如果在放慢 50 倍的速率下表現流暢,假以時(shí)日定能找到運行流暢(′?`)的最大速度?;蛟S正常速度下 5 毫秒的差池很難被注意到,但是放慢速度,它就變得非常明顯了。
尤其是做非常復雜的動(dòng)畫(huà)分析,或者解決非常棘手的性能瓶頸,慢動(dòng)作查看元素會(huì )非常的有用。
重要的一點(diǎn)就是,在慢動(dòng)作下你會(huì )將非常多的(T_T)細節優(yōu)化地完美,當動(dòng)畫(huà)加速之后它將會(huì )給人完??美無(wú)瑕的感覺(jué)。盡管這些都(dou)顯得微不足道,但是用戶(hù)會(huì )注意到動(dòng)畫(huà)效果的流暢和細節??的。
只有 OS X 才有的(de)功能—如果你 shift + 點(diǎn)擊最小化按鈕或者一個(gè)應用圖標,你將會(huì )看見(jiàn)它在緩慢移動(dòng)?;谶@一點(diǎn),我們甚至在陀螺儀上實(shí)現了這個(gè)功能,當你按下 shift 鍵的時(shí)候將會(huì )(╯°□°)╯激活慢動(dòng)作模式。
6、給你的用戶(hù)界面錄個(gè)像,并ヽ(′?`)ノ且在重復播放中得到一個(gè)有價(jià)??值的第三人視角??的看法。
有時(shí)候不同的視角能夠幫助你對事物有更加清楚的認識,而錄像則是一種很好的方法。
有的人會(huì )用 AE 做視??頻然后放到網(wǎng)站上,而我恰恰相反,我總是嘗(′ω`)試將網(wǎng)站界面錄制成很棒的視頻。
發(fā)布視頻其實(shí)門(mén)檻很高的。有一天我對做出來(lái)的東西感(gan)到非常激動(dòng),想記錄下來(lái)和朋友們分享。
然而,當看第二遍的時(shí)候,我發(fā)現了一些瑕疵,時(shí)間節點(diǎn)設置得不那么恰當,并且出??現了一個(gè)延遲尖峰。這讓我有點(diǎn)打退堂鼓了,我發(fā)現還有很多的內容需要優(yōu)化,所以我不能就這么把視頻發(fā)送給朋友。
在使用過(guò)程中這些瑕疵都很容易被掩蓋,但是在視頻中一次次地觀(guān)看慢動(dòng)作的動(dòng)畫(huà)能夠讓一切問(wèn)題都暴露地(O_O)非常明顯。
有人會(huì )說(shuō)拍攝出來(lái)和看起來(lái)的效果并不完全相同,但也許它變更加精確了呢。
這已經(jīng)成為我工作中很重要的一部分,我會(huì )觀(guān)看慢動(dòng)作的視頻并且修改任何我覺(jué)得不妥的地方。其實(shí)也可以很容易地將這類(lèi)問(wèn)題歸咎于瀏覽器性能差,但是再多優(yōu)化一點(diǎn)多測試一點(diǎn),這些問(wèn)題就能夠得到解決。
等到你在視頻中不會(huì )發(fā)現非常尷尬的延遲尖峰,并且感覺(jué)視頻挺好的可以曬出來(lái)了,這個(gè)時(shí)候你的頁(yè)面就可以發(fā)布了。
7、網(wǎng)絡(luò )活動(dòng)可能會(huì )造成延遲。你應該預加載或者延遲處理非常大的 HTTP 請求
圖片便是其中一個(gè)元兇,無(wú)論是幾??個(gè)大圖片(大的背景圖)或者非常多的小圖(五十個(gè)頭像),或者非常多的內容(一個(gè)從頭到尾有很多圖片的長(cháng)頁(yè)面)。
頁(yè)面首次加載的時(shí)候,許多的東西會(huì )被初始化并下載。其中內容解析、廣告和其他第三方腳本會(huì )使性(′?`)能變得更糟糕。有時(shí)候,將動(dòng)畫(huà)效果在頁(yè)面加載后延遲零點(diǎn)幾秒將會(huì )對??性能有很(hen)大的提(ti)升。
如果沒(méi)有必要的話(huà),不要過(guò)度優(yōu)化動(dòng)畫(huà)延遲,一個(gè)復雜的頁(yè)面要求非常精確的延遲和時(shí)間節點(diǎn)才能運行流暢。通常你會(huì )想要在開(kāi)始的時(shí)候加載盡可能少的數據,當主要內容和介紹動(dòng)畫(huà)完成之后(′?ω?`)再繼續加載??其他的內容。
一個(gè)有很多數據的頁(yè)面,需要深思熟慮地加載所有(′ω`)內容。一個(gè)在靜態(tài)頁(yè)面中表現良好的動(dòng)畫(huà)效果也許就會(huì )在實(shí)時(shí)數據的加載中變得緩慢。如果有些內容仿佛應該生效但卻沒(méi)有,或者不能一如既往地流暢表現,我建議檢查一下網(wǎng)絡(luò )活動(dòng),確認一下你是否也在同時(shí)處理其他的內容。
8、不要直接綁定( ???)滾動(dòng)事件。貌似是個(gè)好主意,其實(shí)不然
基于(′?_?`)滾動(dòng)的動(dòng)畫(huà)在前些年一段時(shí)間非?;鸨?,尤其是涉及視差或者其他特效的內容里。它們的設計模式是好是壞仍有待考證,但是在技術(shù)上有著(zhù)良莠不齊的實(shí)現方法。
基于滾動(dòng)(dong)的動(dòng)畫(huà)中??有一種非常流行的處理方式,即將滾動(dòng)一定距離作為事件處理同時(shí)觸發(fā)動(dòng)畫(huà)內容。除非你對自己的行為了如指掌,否則我會(huì )建議不要使用這種方式,因為它真的很容易出錯并且很難維護。
更糟糕的情況是自定義滾動(dòng)條功能,而不用默認的功能—??又名 scroll???jacking 。請不要這么想不開(kāi)。
在這十項準則中,這項尤其適用于移??動(dòng)開(kāi)發(fā),另??外可能也是理想用戶(hù)體驗的好的實(shí)踐。
如果你確實(shí)要求獨特的體驗并且你??ヽ(′?`)ノ希望它基于滾動(dòng)或者其他的特殊事件,我建議創(chuàng )建一個(gè)快速原型來(lái)實(shí)現(′ω`*),而不是費力不討好地去設計事件形式。
9、盡早并且經(jīng)常地在移動(dòng)設備上的測試。
大多數的網(wǎng)站都是在電腦上搭建的,并且最常(′▽?zhuān)?)用本機(′?ω?`)做測試。因此,移動(dòng)端體驗和動(dòng)畫(huà)性能就被次要考慮了。一些技術(shù)(比如 canvas)或者動(dòng)畫(huà)技術(shù)可能在移動(dòng)端表現地并不好。
然而(er),如果代碼寫(xiě)得好優(yōu)化也到位(參考規則 #1),移動(dòng)端的體驗甚至比電腦更加流暢。移動(dòng)端的優(yōu)化是一項非常棘( ?ヮ?)手的事情,但是新的 iPhone 比手提(ti)電腦更快!如果你采用了前幾項建議,你將會(huì )得到一個(gè)非常棒的移動(dòng)端表現。
移動(dòng)端訪(fǎng)問(wèn)網(wǎng)站將會(huì )變得非常非常的重要。我建議你專(zhuān)門(mén)拿一個(gè)星期的時(shí)間認真地用手機查看你的網(wǎng)站,這或許有些極端,你可能會(huì )感覺(jué)像是在接ヾ(′?`)?受懲罰而被迫使用移動(dòng)端版本,但(′▽?zhuān)?(dan)是你應該調整好心態(tài)。
不斷優(yōu)化設計和提高性能,直到網(wǎng)站在移動(dòng)端的表現和在電腦上一樣優(yōu)美和方便。
如果你堅持一周都用移動(dòng)(dong)端來(lái)訪(fǎng)問(wèn)網(wǎng)站,你將會(huì )得到一個(gè)比電┐(′д`)┌腦上更優(yōu)化體(ti)驗更好的網(wǎng)站。即使在使用過(guò)程中遇到非常惱人的事情也是值得的,那意味著(zhù)這(zhe)些問(wèn)題將在你的用戶(hù)體驗到之前就被解決掉了!
10、經(jīng)常在不同的設備上測試,不同屏幕尺寸、分辨率,或者有著(zhù)各種樣式的設備
除了移動(dòng)端和電腦之外還有很多因素能夠對性能產(chǎn)生極大的影響,比如是否是 “retina&rdqu(′▽?zhuān)?o; 屏幕、窗口的分辨率、硬件的老舊程度等等。
即使 Chorme 和 Safari 都是基于 Webkit 的瀏覽器并且有著(zhù)相似的語(yǔ)法,但??是他們也有各自的特點(diǎn)。每一次 Chrome 升級都會(huì )修復一些問(wèn)題同時(shí)也會(huì )引入新的 bug,所以你必??須時(shí)刻保持警惕。
當然,你不會(huì )只??想著(zhù)搭建一個(gè)對于所有瀏覽器放之四海而皆準的網(wǎng)站,所以尋找一個(gè)(?_?;)靈活的方法以便于你能夠增加或者移除一些功能是非常有用的。
我通常會(huì )交替在較小的 MacBook Air 和大屏的 iMac 中使用網(wǎng)站,每次都會(huì )暴露出新的問(wèn)題然后再修復 — 尤其是動(dòng)畫(huà)性能方面的問(wèn)題,有時(shí)候也會(huì )有全局設計的題、信息密度、可讀性的問(wèn)題等等。
Media queries 是一款非常強大的工具,它典型的用處是定位由于高度或者寬度造成的樣式差異,但是它同樣能夠用來(lái)根據分辨率添加目標內容或者( ?ω?)其他屬性。另外,識別系統和設備類(lèi)型的功能也是非常有用的,因為移動(dòng)設備的性能特征和電腦還是有很大區別的。
原文:10 principles for smooth web animations
原文作者:Anand Sharma
譯文出自:掘金翻譯計劃
譯者:王子建
校對者:Scarecrow,Gヾ(′?`)?ocy