梅須遜雪三分白,雪卻輸梅一段香——CSS動畫與JavaScript動畫

CSS動畫並非絕對比JavaScript動畫性能更優越,開源動畫庫Velocity.js等就展示了強勁的性能。javascript

1、二者的主要區別

先開門見山的說說二者之間的區別。css

1)CSS動畫:html

基於CSS的動畫通常由瀏覽器「主線程」以外的獨立線程處理,在其中執行樣式、佈局、繪製和 JavaScript。前端

使用CSS動畫,容許對單個動畫關鍵幀、持續時間和迭代進行更多控制。html5

但缺少表現力,而且很難有意義地組織動畫,這意味着創造動畫會帶來較高的複雜度和錯誤率。java

 

2)JavaScript動畫:css3

在瀏覽器主線程的JavaScript中運行,主線程已經忙於運行其餘的JavaScript,樣式的計算,佈局還有繪製。線程內存在資源競爭,這實質上增長了掉幀的風險。git

基於JavaScript的動畫靈活性更高,徹底控制元素在每一個步驟,能更好的實現複雜的動畫和大量的交互(例如當要求全部的元素在頁面加載時順次加載顯示出來)github

對於多元素多步驟的動畫序列、交互拖拽動畫等,用JavaScript實現則是上選。web

 

2、頁面渲染

1)步驟

爲了能讓動畫高性能的執行,得先了解一下頁面渲染。

頁面渲染的通常過程爲JavaScript > 計算樣式 > 佈局 > 繪製 > 渲染層合併。

Layout:計算每一個DOM元素最終在屏幕上顯示的大小和位置。頁面中一個元素的佈局發生變化,會聯動地引起其餘元素的佈局發生變化。

Paint:繪製文字、顏色、邊框和陰影等,也就是一個DOM元素全部的可視效果。這個繪製過程可能會在多個層上完成的。

Composite:在每一個層上完成繪製以後,瀏覽器會將全部層按照合理的順序合併成一個圖層,而後顯示在屏幕上。

 

2)優化

Layout(重排)Paint(重繪)是整個環節中最爲耗時的兩環,因此咱們儘可能避免着這兩個環節。

爲了實現上述效果,就須要只使用那些僅觸發Composite的屬性。

能夠選擇transformopacityanimate.css中不少的動畫都是用這兩個屬性實現的。

Css Triggers的網頁中能夠看到兩個屬性的描述:

多層繪製方式的好處是,使用tranform來實現移動效果的元素將會被正常繪製,同時不會觸發對其餘元素的繪製。

H5動畫60fps之路》中經過一張圖,總結了一些針對性的優化方法:

優化方法中提到了一個屬性will-change,能夠將元素提高爲合成層,不過兼容性不太友好。

對於不支持此屬性的,可使用一個3D transform屬性來強制瀏覽器建立一個新的渲染層,也就是人們常說的硬件加速。

.css{
  transform: translate3d(0,0,0);
}

作過一個大轉盤抽獎的項目,當使用「transform:rotate(0deg)」沒有建立一個新的渲染層,那麼就會在不停的重繪,高亮的地方就是重繪。

當改用「transform:rotate3d(0,0,1,0deg)」新增一個渲染層後,只會重繪一次,在電腦上看不出性能區別,在手機上就會很是明顯,卡的不能動。

3)工具

在Chrome瀏覽器中,有工具能夠查看到重繪與合成層。

Paint Flashing:就是看重繪,重繪的地方會高亮。

Layer Borders:黃褐色就是合成層,青色的細線是瀏覽器渲染時候的「瓦片」,瀏覽器繪製頁面的時候只會繪製可視區域必定範圍內的瓦片,以節省性能開銷。

 

 

3、動畫相關事件

1)CSS動畫事件

CSS動畫有兩種方式設置Transition過渡和Animation

與過渡相關事件只有一個TransitionEnd,也就是在過渡結束後觸發。

animation相關事件有三個,animationstart、animationiteration與animationend。

兩個動做相關的事件比較少,因此控制動畫很是有限制,應對複雜場景蠻吃力的。

 

2)requestAnimationFrame

requestAnimationFrame函數就是針對動畫效果的API,與顯示器固定的刷新頻率保持同步,利用這個刷新頻率進行頁面重繪,通常來講,這個頻率爲每秒60幀。

此外,一旦頁面不處於瀏覽器的當前標籤,就會自動中止刷新,這就節省了CPU、GPU和電力。

這個函數是在主線程上完成,若是主線程很是繁忙,那麼動畫效果會下降。

咱們經常使用的setInterval、setTimeout是開發者主動要求瀏覽器去繪製,由於動畫不會與屏幕的刷新率同步,極可能出現抖動和跳幀。

各個瀏覽器對此函數的支持程度不同,可能須要添加前綴,也可能須要Polyfill一下。

window.requestAnimFrame = (function() {
  return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(callback) {
      window.setTimeout(callback, 1000 / 60);
    };
})();

上面的代碼按照1秒鐘60次(大約每16.7毫秒一次),來模擬requestAnimationFrame。

 

 

參考資料:

JavaScript動畫漫談

CSS3動畫和js動畫各有什麼優劣

CSS vs JS動畫:誰更快?

CSS 對比 JavaScript 動畫

CSS VS JavaScript動畫

前端性能優化之更平滑的動畫

簡化繪製的複雜度、減少繪製區域

優先使用渲染層合併屬性、控制層數量

動畫與性能

補間動畫

JavaScript動畫實現初探

消除疑問:CSS動畫 VS. JavaScript

High Performance Animations

打造H5動感影集的愛恨情仇(動畫性能篇)

HTML5探祕:用requestAnimationFrame優化Web動畫

Chrome渲染分析之Rendering工具使用(1)

Chrome渲染分析之Rendering工具使用(2)

Chrome 渲染優化 - 層模型

無線性能優化:Composite

CSS3硬件加速也有坑

相關文章
相關標籤/搜索