CSS動畫原理及硬件加速


一、圖層

  圖層即層疊上下文,具體概念和應用大家可以看我之前轉自張鑫旭大神博客的《CSS層疊上下文和層疊順序》,這里我們簡單復習一下產生層疊上下文的原因。

1.根層疊上下文
  指的是頁面根元素,也就是滾動條的默認的始作俑者<html>元素。這就是為什么,絕對定位元素在left/top等值定位的時候,如果沒有其他定位元素限制,會相對瀏覽器窗口定位的原因。

2.定位元素與傳統層疊上下文
  對於包含有position:relative/position:absolute的定位元素,以及FireFox/IE瀏覽器(不包括Chrome等webkit內核瀏覽器)(目前,也就是2016年初是這樣)下含有position:fixed聲明的定位元素,當其z-index值不是auto的時候,會創建層疊上下文。

3.CSS3與新時代的層疊上下文

  以下情況會產生新的層疊上下文:

  • 根元素(HTML)
  • 絕對或相對定位且 z-index 值不為 auto
  • 一個伸縮項目 Flex Item,且 z-index 值不為 auto,即父元素 display: flex|inline-flex
  • 元素的 opacity 屬性值小於 1
  • 元素的 transform 屬性值不為 none
  • 元素的 mix-blend-mode 屬性值不為 normal
  • 元素的 filter 屬性值不為 normal
  • 元素的 isolation 屬性值為 isolate
  • position: fixed
  • will-change 中指定了上述任意屬性,即便你沒有直接定義這些屬性
  • 元素的 -webkit-overflow-scrolling 屬性值為 touch

 

二、利用絕對定位+top/left實現動畫

CSS動畫之硬件加速

  上圖數據中的綠色條紋表示的就是使用 top 和 left 實現動畫時瀏覽器發生的 repaint 操作,從中可以看出動畫幀數遠低於60 幀。

  從 chrome 的開發者工具按 ESC 之后選擇 “rendering” 面板,我們可以通過選中“Enable piant flashing”來進一步監測 repaint 操作。開啟該選項后,頁面中的 repaint 區域就會被綠色蒙版高亮顯示出來。重新使用 top 和 left 的示例演示的話,你會發現包裹球的那塊區域會一直閃爍綠色的蒙版。

CSS動畫之硬件加速

  按照常理來說,改變元素位置會產生重排,為什么上面圖中顯示的全是重繪呢?原因是絕對定位會建立一個新的圖層,而此圖層上只有當前一個元素,多以只會重繪,而不會重排。這也告訴我們,在同一層中,元素數量少的情況下,重排性能對更好,速度會更快。

 

三、transform2D實現動畫

  下圖是使用CSS transform 檢測到的數據:

CSS動畫之硬件加速

  如你所見,動畫演示期間並沒有過多的 repaint 操作。

  那么,為什么 transform 沒有觸發 repaint 呢?簡而言之,transform 動畫由GPU控制,支持硬件加速,並不需要軟件方面的渲染。

 

四、硬件加速原理

  瀏覽器接收到頁面文檔后,會將文檔中的標記語言解析為DOM樹。DOM樹和CSS結合后形成瀏覽器構建頁面的渲染樹。渲染樹中包含了大量的渲染元素,每一個渲染元素會被分到一個圖層中,每個圖層又會被加載到GPU形成渲染紋理,而圖層在GPU中transform 是不會觸發 repaint 的,最終這些使用 transform 的圖層都會由獨立的合成器進程進行處理。

  在我們的示例中,CSS transform 創建了一個新的復合圖層,可以被GPU直接用來執行 transform 操作。在chrome開發者工具中開啟“show layer borders”選項后,每個復合圖層就會顯示一條黃色的邊界:

  示例中的球就處於一個獨立的復合圖層,移動時的變化也是獨立的:

CSS動畫之硬件加速

此時,你也許會問:瀏覽器什么時候會創建一個獨立的復合圖層呢?事實上一般是在以下幾種情況下:

  • 3D 或者 CSS transform
  • <video> 和 <canvas> 標簽
  • CSS filters
  • 元素覆蓋時,比如使用了 z-index 屬性

等一下,上面的示例使用的是 2D transition 而不是 3D 的 transforms 啊?這個說法沒錯,所以在timeline中我們可以看到:動畫開始和結束的時候發生了兩次 repaint 操作。

CSS動畫之硬件加速

  3D 和 2D transform 的區別就在於,瀏覽器在頁面渲染前為3D動畫創建獨立的復合圖層,而在運行期間為2D動畫創建。動畫開始時,生成新的復合圖層並加載為GPU的紋理用於初始化 repaint。然后由GPU的復合器操縱整個動畫的執行。最后當動畫結束時,再次執行 repaint 操作刪除復合圖層。

 

五、強制GPU渲染

  並不是所有的CSS屬性都能觸發GPU的硬件加速(圖層在GPU中屬性改變不會觸發 repaint ),實際上只有少數屬性可以,比如下面的這些:

  • transform
  • opacity
  • filter

  為了避免 2D transform 動畫在開始和結束時發生的 repaint 操作,我們可以硬編碼一些樣式來解決這個問題:

.example1 {
  transform: translateZ(0);
}

.example2 {
  transform: rotateZ(360deg);
}

  這段代碼的作用就是讓瀏覽器執行 3D transform。瀏覽器通過該樣式創建了一個獨立圖層,圖層中的動畫則有GPU進行預處理並且觸發了硬件加速。

  如果某一個元素的背后是一個復雜元素,那么該元素的 repaint 操作就會耗費大量的資源,此時也可以使用上面的技巧來減少性能開銷。

 

六、使用硬件加速的問題

  使用硬件加速並不是十全十美的事情,比如:

  • 內存。如果GPU加載了大量的紋理,那么很容易就會發生內容問題,這一點在移動端瀏覽器上尤為明顯,所以,一定要牢記不要讓頁面的每個元素都使用硬件加速。
  • 使用GPU渲染會影響字體的抗鋸齒效果。這是因為GPU和CPU具有不同的渲染機制。即使最終硬件加速停止了,文本還是會在動畫期間顯示得很模糊。

 

七、總結

  感覺這里面邏輯很亂,在這里整理一下。首先transform和絕對定位都會產生新的圖層,所以都不存在重排,圖層在GPU中transform又不會引起重繪,這就是硬件加速的原理。另外,transform3D和2D的區別在於3D渲染前便會產生新的圖層,而2D是在運行時產生圖層,運行結束時刪除圖層。

 

注:本文在整理了南北在W3C上寫的《CSS動畫之硬件加速》中的知識點,並加入了自己的理解和總結


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM