也許你不知道,JS animation比CSS更快!

發表於2017-12-07
CSS vs. JS Animation: 哪個更快?

基於JavaScript的動畫竟然已經默默地比CSS的transition動畫快了?而且,Adobe和 Google竟然一直在釋出可以媲美原生應用的富媒體移動站點?

這篇文章將會逐點講解基於JavaScript的DOM動畫庫,比如Velocity.js和GSAP,是如何比jQuery和基於CSS的動畫庫高效的。

jQuery

讓我們先從這個事實開始:JavaScript和jQuery被錯誤的混淆了。JavaScript的動畫是快的,但是jQuery的動畫慢。為什麼?因為雖然jQuery很強大,但是它的目標從來不是為了成為一個高效的動畫引擎。

  • jQuery不能避免佈局震盪因為它的程式碼除了動畫還提供了很多功能。
  • jQuery的記憶體消耗經常觸發垃圾回收,導致動畫卡住
  • jQuery使用setInterval而不是requestAnimationFrame (RAF)為了避免一些bug

注意,佈局震盪引起了動畫開始處的卡頓,垃圾回收導致了動畫進行中的卡頓,RAF的缺席導致了幀率低。

實現的例子

避免佈局震盪,包括簡單地合併DOM查詢和DOM更新:

發生在更新之後的查詢會強制瀏覽器立馬重新佈局,並計算給出頁面樣式的計算值(把更新的影響考慮在內)。這對於執行於16ms間隔的動畫來講,會產生巨大的開銷。

同樣,實現RAF並不需要對既有程式碼改動很大。讓我們來對比一下RAF的實現和setInterval的實現:

RAF極大限度地提高了動畫的效能。而您只需要修改為數不多的程式碼。

CSS Transitions

CSS transitions的動畫效能優於jQuery,它把動畫的邏輯交給了瀏覽器本身。這會有助於:1)優化DOM互動和記憶體消耗以避免卡頓,2)在底層藉助RAF的特性,3)強制硬體加速(藉助GPU的能力來提高動畫效能)。

然而,實際情況是,這些優化可以直接通過JavaScript來實現,GSAP已經致力於此多年。Velocity.js,一個新的動畫引擎,不止藉助於上述技術,還應用了其他方法–我們將很快探討。

明白JavaScript動畫可以媲美CSS動畫庫這一事實,只是我們計劃的第一步。第二步是我們要明白JavaScript動畫可以比CSS動畫還快。

讓我們從檢查CSS動畫庫的缺陷開始:

  • Transitions的強制硬體加速是使GPU加速,然而這反而會導致GPU強壓狀況下動畫的卡頓。這些影響在移動裝置上更為嚴重。(特別地,這個卡頓是由於資料在瀏覽器的主執行緒和排序執行緒間傳遞的開銷導致的。一些CSS屬性,比如transforms和opacity,是不受這個開銷影響的。)Adobe在這裡闡述了這個問題。
  • Transitions在IE10以下有相容問題, 這在PC端站點會很容易導致問題發生,因為IE8和IE9依然很流行
  • 因為transitions並不是被JavaScript控制(它們只是被JavaScript觸發),瀏覽器並不知道如何同步地使用JavaScript程式碼來操控優化transitions。

相反地:基於JavaScript的動畫庫,可以自己決定什麼時候使用硬體加速,可以相容所有版本的IE,並且它們非常適合批量動畫優化。

我的建議是,當您只是開發移動站點,並且您的動畫只包含簡單的狀態變化時,可以使用原生CSS transitions。在這種情況下,transitions算是一種高效並且原生的解決方案,並且可以把所有的動畫邏輯只放在css中,避免了因為引入JavaScript庫而導致頁面臃腫。但是,如果您正在設計複雜的UI,或者正在開發具有狀態UI的應用程式,請使用JavaScript動畫庫,它可以使您的動畫保持高效能,使您的工作流程保持可控。特別是在管理CSStransitions方面做得很棒的一個庫是 Transit

JavaScript Animation

Okay,所以JavaScript在效能上可以佔上風。但是JavaScript究竟可以快多少呢?其實,它已經快到可以建立複雜的,通常只能用WebGL構建的3D animation demo。已經快到可以建立通常只能用Flash或者影效處理做到的multimedia teaser。已經快到可以建立通常只能用canvas構建的virtual world

為了直觀比較動畫庫的領先效能,包括Transit(內部使用CSS transitions),請查閱Velocity的文件,在VelocityJS.org

依然存在問題:JavaScript究竟如何達到高效能?下面是基於JavaScript的動畫庫能實現的優化列表:

  • 為了減小布局震盪,將整個動畫中涉及到DOM同步化到堆疊中。
  • 快取鏈式呼叫中的屬性值,以儘量減少DOM查詢(它是影響DOM動畫效能的致命弱點)的發生。
  • 在同一個跨同級元素呼叫中快取單位轉換比率(例如PX到%、em等)。
  • 當樣式更新在視覺上不明顯時,跳過更新。

回顧之前講的佈局震盪,Velocity.js利用這些最佳實踐來快取動畫的結束值,這些值會被重用為之後動畫的開始值,從而避免再次查詢DOM元素的初始值:

在上面的例子中,第二個Velocity自動知道它應該從opacity為1,top為50%開始。

瀏覽器最終可以自己執行很多相同的優化,但這樣做將需要極大地限制開發人員編寫動畫程式碼的方式。因此,同樣的原因,jQuery不使用RAF(見上文),瀏覽器也永遠不會強加優化,即使這些優化只有非常小的可能會打破規範或偏離預期的行為。

最後,讓我們來比較一下這兩個JavaScript動畫庫(Velocity.js和GSAP)。

  • GSAP是一種快速、功能豐富的動畫平臺。Velocit是一個輕量級工具,可以極大地提高UI動畫效能和工作流程。
  • GSAP需要許可費。Velocity是通過許MIT開源的。
  • 效能都很優異,GSAP和Velocity在真實專案中沒有區別。

我的建議是:當您需要精確的控制(例如重映,暫停/恢復/搜尋)、運動(例如Bezier曲線路徑),或複雜的分組/排序時,使用GSAP。這些特性對於遊戲開發和某些niche應用非常重要,但在Web應用程式的UI中並不常見。

Velocity.js

定位GSAP功能豐富,並不意味著Velocity功能單一。相反地,在壓縮後只有7Kb的檔案中,Velocity不僅提供了jQuery$.animate()的所有功能,而且提供了color animation,transforms,loops,easings,class animation和scrolling。

簡而言之,Velocity是jQuery、jQuery UI和CSStransitions的最佳組合。

進一步,從方便的角度,Velocity在底層使用jQuery的$.queue()方法,因此可以無縫地與jQuery的$.animate(), $.fade()$.delay()函式互動。並且,由於Velocity的語法和$.animate()一致,您頁面的程式碼不需要修改

讓我們快速看一下Velocity.js。在基礎動畫上,Velocity和$.animate()一樣:

在高階動畫上,複雜的滾動場景和三維動畫都可以建立——只需要兩行簡單的程式碼:

結束語

Velocity的目標是保持領先的DOM動畫效能和便捷。本文的重點是前者。請去VelocityJS.org學習更多關於後者的知識。

在我們結束之前,記得*一個高效能的UI不僅僅是選擇合適的動畫庫。頁面的其餘部分也應該優化。從下面這些奇妙的Google話題中學習更多:

相關文章