正巧看到在送書,因而乎找了找本身博客上記錄過的一些東西來及其無恥的蹭書了~~~html
小廣告:更多內容能夠看個人博客html5
最近拜讀了一下html5rocks上幾位大神寫的一篇關於CSS3動畫性能優化的文章,學到了不少,在這裏記錄一下,其中的知識都是來源於這倆篇文章,我只是截取了其中比較關注的內容出來,原文地址High Performance Animations及Accelerated Rendering in Chromeweb
現代瀏覽器在使用CSS3動畫時,如下四種情形繪製的效率較高,分別是:
* 改變位置
* 改變大小
* 旋轉
* 改變透明度canvas
首先要了解CSS的圖層的概念(Chrome瀏覽器)瀏覽器
瀏覽器在渲染一個頁面時,會將頁面分爲不少個圖層,圖層有大有小,每一個圖層上有一個或多個節點。在渲染DOM的時候,瀏覽器所作的工做其實是:
1. 獲取DOM後分割爲多個圖層
2. 對每一個圖層的節點計算樣式結果(Recalculate style--樣式重計算)
3. 爲每一個節點生成圖形和位置(Layout--迴流和重佈局)
4. 將每一個節點繪製填充到圖層位圖中(Paint Setup和Paint--重繪)
5. 圖層做爲紋理上傳至GPU
6. 符合多個圖層到頁面上生成最終屏幕圖像(Composite Layers--圖層重組)性能優化
Chrome中知足如下任意狀況就會建立圖層:
* 3D或透視變換(perspective transform)CSS屬性
* 使用加速視頻解碼的<video>
節點
* 擁有3D(WebGL)上下文或加速的2D上下文的<canvas>
節點
* 混合插件(如Flash)
* 對本身的opacity作CSS動畫或使用一個動畫webkit變換的元素
* 擁有加速CSS過濾器的元素
* 元素有一個包含複合層的後代節點(一個元素擁有一個子元素,該子元素在本身的層裏)
* 元素有一個z-index
較低且包含一個複合層的兄弟元素(換句話說就是該元素在複合層上面渲染)多線程
須要注意的是,若是圖層中某個元素須要重繪,那麼整個圖層都須要重繪。好比一個圖層包含不少節點,其中有個gif圖,gif圖的每一幀,都會重回整個圖層的其餘節點,而後生成最終的圖層位圖。因此這須要經過特殊的方式來強制gif圖屬於本身一個圖層(translateZ(0)
或者translate3d(0,0,0)
),CSS3的動畫也是同樣(好在絕大部分狀況瀏覽器本身會爲CSS3動畫的節點建立圖層)ide
簡化一下上述過程,每一幀動畫瀏覽器可能須要作以下工做:
1. 計算須要被加載到節點上的樣式結果(Recalculate style--樣式重計算)
2. 爲每一個節點生成圖形和位置(Layout--迴流和重佈局)
3. 將每一個節點填充到圖層中(Paint Setup和Paint--重繪)
4. 組合圖層到頁面上(Composite Layers--圖層重組)佈局
若是咱們須要使得動畫的性能提升,須要作的就是減小瀏覽器在動畫運行時所須要作的工做。最好的狀況是,改變的屬性僅僅印象圖層的組合,變換(transform
)和透明度(opacity
)就屬於這種狀況性能
現代瀏覽器如Chrome,Firefox,Safari和Opera都對變換和透明度採用硬件加速,但IE10+不是很肯定是否硬件加速
有些節點,當你改變他時,會須要從新佈局(這也意味着須要從新計算其餘被影響的節點的位置和大小)。這種狀況下,被影響的DOM樹越大(可見節點),重繪所須要的時間就會越長,而渲染一幀動畫的時間也相應變長。因此須要盡力避免這些屬性
一些經常使用的改變時會觸發重佈局的屬性:
盒子模型相關屬性會觸發重佈局:
* width
* height
* padding
* margin
* display
* border-width
* border
* min-height
定位屬性及浮動也會觸發重佈局:
* top
* bottom
* left
* right
* position
* float
* clear
改變節點內部文字結構也會觸發重佈局:
* text-align
* overflow-y
* font-weight
* overflow
* font-family
* line-height
* vertival-align
* white-space
* font-size
這麼多經常使用屬性都會觸發重佈局,能夠看到,他們的特色就是可能修改整個節點的大小或位置,因此會觸發重佈局
若是在網頁中使用CSS的類來對節點作狀態標記,當這些節點的狀態標記類修改時,將會觸發節點的重繪和重佈局。因此在節點上使用CSS類來作狀態比較是代價很昂貴的
修改時只觸發重繪的屬性有:
* color
* border-style
* border-radius
* visibility
* text-decoration
* background
* background-image
* background-position
* background-repeat
* background-size
* outline-color
* outline
* outline-style
* outline-width
* box-shadow
這樣能夠看到,這些屬性都不會修改節點的大小和位置,天然不會觸發重佈局,可是節點內部的渲染效果進行了改變,因此只須要重繪就能夠了
在重繪時,這些節點會被加載到GPU中進行重繪,這對移動設備如手機的影響仍是很大的。由於CPU不如臺式機或筆記本電腦,因此繪畫巫妖的時間更長。並且CPU與GPU之間的有較大的帶寬限制,因此紋理的上傳須要必定時間
須要注意的是,上面那些觸發重繪的屬性裏面沒有opacity
(透明度),很奇怪不是嗎?實際上透明度的改變後,GPU在繪畫時只是簡單的下降以前已經畫好的紋理的alpha值來達到效果,並不須要總體的重繪。不過這個前提是這個被修改opacity
自己必須是一個圖層,若是圖層下還有其餘節點,GPU也會將他們透明化
在Blink和WebKit的瀏覽器中,一當一個節點被設定了透明度的相關過渡效果或動畫時,瀏覽器會將其做爲一個單獨的圖層,但不少開發者使用translateZ(0)
或者translate3d(0,0,0)
去使瀏覽器建立圖層。這種方式能夠消除在動畫開始以前的圖層建立時間,使得動畫儘快開始(建立圖層和繪製圖層仍是比較慢的),並且不會隨着抗鋸齒而導出突變。不過這種方法須要節制,不然會由於建立過多的圖層致使崩潰
Chrome中,非根圖層以及透明圖層使用grayscale antialiasing而不是subpixel antialiasing,若是抗鋸齒方法變化,這個效果將會很是顯著。若是你打算預處理一個節點而不打算等到動畫開始,能夠經過這種強迫瀏覽器建立圖層的方式進行
咱們經過節點的transform
能夠修改節點的位置、旋轉、大小等。咱們日常會使用left
和top
屬性來修改節點的位置,但正如上面所述,left
和top
會觸發重佈局,修改時的代價至關大。取而代之的更好方法是使用translate
,這個不會觸發重佈局
咱們常常面臨一個抉擇:是使用JavaScript的動畫仍是使用CSS的動畫,下面將對比一下這兩種方式
缺點:JavaScript在瀏覽器的主線程中運行,而其中還有不少其餘須要運行的JavaScript、樣式計算、佈局、繪製等對其干擾。這也就致使了線程可能出現阻塞,從而形成丟幀的狀況。
優勢:JavaScript的動畫與CSS預先定義好的動畫不一樣,能夠在其動畫過程當中對其進行控制:開始、暫停、回放、停止、取消都是能夠作到的。並且一些動畫效果,好比視差滾動效果,只有JavaScript可以完成
缺點:缺少強大的控制能力。並且很難以有意義的方式結合到一塊兒,使得動畫變得複雜且易於出問題。 優勢:瀏覽器能夠對動畫進行優化。它必要時能夠建立圖層,而後在主線程以外運行。
Google目前正在探究經過JS的多線程(Web Workers)來提供更好的動畫效果,而不會觸發重佈局及樣式重計算
動畫給予了頁面豐富的視覺體驗。咱們應該盡力避免使用會觸發重佈局和重繪的屬性,以避免失幀。最好提早申明動畫,這樣能讓瀏覽器提早對動畫進行優化。因爲GPU的參與,如今用來作動畫的最好屬性是以下幾個:* opacity* translate* rotate* scale