動畫卡頓是在移動web開發時經常遇到的問題,解決這個問題一般會用到css3硬件加速。
css3硬件加速這個名字感覺上很高大上,其實它做的事情可以簡單概括為:通過GPU進行渲染,解放cpu。
現象
通過對比不使用css3加速和使用css3加速兩個例子,我們可以看到兩者渲染的差異:
前者通過改變top和left
屬性進行動畫,fps維持在47左右,cpu一直進行計算;后者通過transform
實現,fps在62左右,cpu基本不需要計算。對比可知通過transform
不僅提升了渲染性能,也解放了cpu。
原理
DOM樹和CSS結合后形成渲染樹。渲染樹中包含了大量的渲染元素,每一個渲染元素會被分到一個圖層中,每個圖層又會被加載到GPU形成渲染紋理。GPU中transform是不會觸發 repaint 的,這一點非常類似3D繪圖功能,最終這些使用 transform的圖層都會由獨立的合成器進程進行處理。
通過chrome的timeline工具,綠色框代表需要repaint的部分,橙色框代表渲染圖層,對比兩者可知采用的css3硬件加速后,不會進行repaint操作,而只會產生一個渲染圖層,GPU就負責操作這個渲染圖層。
復合圖層
在原理中我們提到transform會創建一個圖層,GPU會來執行transform的操作,這個圖層且稱為復合圖層(composited layer)。
雖然 Chrome 的啟發式方法(heuristic)隨著時間在不斷發展進步,但是從目前來說,滿足以下任意情況便會創建層:
- 3D 或透視變換(perspective transform) CSS 屬性
- 使用加速視頻解碼的元素,如<video>
- 擁有 3D (WebGL) 上下文或加速的 2D 上下文的元素,如<canvas>
- 混合插件(如 Flash)
- 對自己的 opacity 做 CSS 動畫或使用一個動畫 webkit 變換的元素
- 擁有加速 CSS 過濾器的元素,如CSS filters
- 元素有一個包含復合層的后代節點(換句話說,就是一個元素擁有一個子元素,該子元素在自己的層里)
- 元素有一個 z-index 較低且包含一個復合層的兄弟元素(換句話說就是該元素在復合層上面渲染)
如果頁面建立了過多的復合圖層,同樣也會造成頁面的卡頓。在CSS3硬件加速也有坑這篇文章中,作者介紹了由于z-index造成復合圖層過多而引發的問題,在以后開發時可以借鑒。可以調試圖層過多卡頓頁面了解z-idnex對圖層創建的影響。
啟用
如下幾個css屬性可以觸發硬件加速:
- transform
- opacity
- filter
- will-change:哪一個屬性即將發生變化,進而進行優化。
上面的的例子中用到的是transform 2D,它是在運行時才會創建圖層,因此在動畫開始和結束時會進行repaint操作;而瀏覽器在渲染前就為transform 3D創建了圖層。
可以通過transform的3D屬性強制開啟GPU加速:
transform: translateZ(0);
transform: rotateZ(360deg);
注意事項
- 不能讓每個元素都啟用硬件加速,這樣會暫用很大的內存,使頁面會有很強的卡頓感。
- GPU渲染會影響字體的抗鋸齒效果。這是因為GPU和CPU具有不同的渲染機制,即使最終硬件加速停止了,文本還是會在動畫期間顯示得很模糊。
參考文章:
- CSS動畫之硬件加速:作者比較詳細介紹了硬件加速,總結的很到位。
- CSS3硬件加速也有坑: 作者介紹了由于z-index造成復合圖層過多,以后開發加以注意。
- 使用CSS3 will-change提高頁面滾動、動畫等渲染性能: will-change的介紹
- javascript性能優化-repaint和reflow:性能殺手以及優化方法。
- 兩張圖解釋CSS動畫的性能:比較詳細對比了采用硬件加速和不采用硬件加速的流程差異。