現代瀏覽器大都可以利用GPU來加速頁面渲染。每個人都痴迷於60楨每秒的順滑動畫。在GPU的眾多特性之中,它可以存儲一定數量的紋理(一個矩形的像素點集合)並且高效地操作這些紋理(比如進行特定的移動、縮放和旋轉操作)。這些特性在實現一個流暢的動畫時特別有用。瀏覽器不會在動畫的每一幀都繪制一次,而是生成DOM元素的快照,並作為GPU紋理(也被叫做層)存儲起來。之后瀏覽器只需要告訴GPU去轉換指定的紋理來實現DOM元素的動畫效果。這就叫做
GPU合成,也經常被稱這種借助於顯卡的優勢改變渲染操作:通常被籠統的稱為“硬件加速(hardware acceleration)”。
“注”:fps:幀/秒(frames per second)的縮寫,也稱為幀速率。是指1秒鍾時間里刷新的圖片的幀數
GPU(Graphic Processing Unit,圖形處理器)。GPU是相對於CPU的一個概念,由於在現代的計算機中圖形的處理變得越來越重要,需要一個專門的圖形的核心處理器。在瀏覽器中用css開啟硬件加速,使GPU發揮功能。CSS animations, transforms 以及 transitions 不會自動開啟GPU加速,而是由瀏覽器的緩慢的軟件渲染引擎來執行。那我們怎樣才可以切換到GPU模式呢,很多瀏覽器提供了某些觸發的CSS規則。現在,像Chrome, FireFox, Safari, IE9+和最新版本的Opera都支持硬件加速,當它們檢測到頁面中某個DOM元素應用了某些CSS規則時就會開啟,最顯著的特征的元素的3D變換。在一些不需要3D效果的時候需要一些技巧開啟硬件加速,例如:為動畫DOM元素添加CSS3樣式
-webkit-transform.:transition3d(0,0,0)或
-webkit-transform.:translateZ(0);,這兩個屬性都會開啟
GPU硬件加速模式,從而讓瀏覽器在渲染動畫時從CPU轉向GPU
.cube { -webkit-transform: translateZ(0); -moz-transform: translateZ(0); -ms-transform: translateZ(0); -o-transform: translateZ(0); transform: translateZ(0); /* Other transform properties here */ }
在webkit內核的瀏覽器中,另一個行之有效的方法是
.cube { -webkit-transform: translate3d(0, 0, 0); -moz-transform: translate3d(0, 0, 0); -ms-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); /* Other transform properties here */ }
原生的移動端應用總是可以很好的運用GPU,這是為什么它比網頁應用(Web apps)表現更好的原因。硬件加速在移動端尤其有用,因為它可以有效的減少資源的利用。如果通過你的測試,結果確是提高了性能,你才可以使用這些方法。使用GPU可能會導致嚴重的性能問題,因為它增加了內存的使用,而且它會減少移動端設備的電池壽命。
硬件加速的工作原理:
瀏覽器接收到頁面文檔后,會將文檔中的標記語言解析為DOM樹。DOM樹和CSS結合后形成瀏覽器構建頁面的渲染樹。渲染樹中包含了大量的渲染元素,每一個渲染元素會被分到一個圖層中,每個圖層又會被加載到GPU形成渲染紋理,而圖層在GPU中
transform
是不會觸發 repaint 的,這一點非常類似3D繪圖功能,最終這些使用
transform
的圖層都會由獨立的合成器進程進行處理。
3D 和 2D transform 的區別就在於,瀏覽器在頁面渲染前為3D動畫創建獨立的復合圖層,而在運行期間為2D動畫創建。動畫開始時,生成新的復合圖層並加載為GPU的紋理用於初始化 repaint。然后由GPU的復合器操縱整個動畫的執行。最后當動畫結束時,再次執行 repaint 操作刪除復合圖層。
使用 GPU 渲染元素,並不是所有的CSS屬性都能觸發GPU的硬件加速,實際上只有少數屬性可以,比如下面的這些:
transform
opacity
filter
如果某一個元素的背后是一個復雜元素,那么該元素的 repaint 操作就會耗費大量的資源,此時也可以使用上面的技巧來減少性能開銷。
使用硬件加速的注意事項
使用硬件加速並不是十全十美的事情,比如:
- 內存。如果GPU加載了大量的紋理,那么很容易就會發生內容問題,這一點在移動端瀏覽器上尤為明顯,所以,一定要牢記不要讓頁面的每個元素都使用硬件加速。
- 使用GPU渲染會影響字體的抗鋸齒效果。這是因為GPU和CPU具有不同的渲染機制。即使最終硬件加速停止了,文本還是會在動畫期間顯示得很模糊。
層創建標准
什么情況下能使元素獲得自己的層?雖然 Chrome 的啟發式方法(heuristic)隨着時間在不斷發展進步,但是從目前來說,滿足以下任意情況便會創建層:
- 3D 或透視變換(perspective transform) CSS 屬性
- 使用加速視頻解碼的 元素
- 擁有 3D (WebGL) 上下文或加速的 2D 上下文的 元素
- 混合插件(如 Flash)
- 對自己的 opacity 做 CSS 動畫或使用一個動畫 webkit 變換的元素
- 擁有加速 CSS 過濾器的元素
- 元素有一個包含復合層的后代節點(換句話說,就是一個元素擁有一個子元素,該子元素在自己的層里)
- 元素有一個 z-index 較低且包含一個復合層的兄弟元素(換句話說就是該元素在復合層上面渲染)
主要是最后一條,如果有一個元素,它的兄弟元素在復合層中渲染,而這個兄弟元素的z-index比較小,那么這個元素(不管是不是應用了硬件加速樣式)也會被放到復合層中。
這類問題尤其是用了輪播、動畫loading的頁面,出現這問題很常見。另外推薦在追查性能問題的時候打開『show composited layer borders』選項,如果頁面有很多黃色的框肯定是不對的。最可怕的是,瀏覽器有可能給復合層之后的所有相對或絕對定位的元素都創建一個復合層來渲染。使用3D硬件加速提升動畫性能時,最好給元素增加一個z-index屬性,人為干擾復合層的排序,可以有效減少chrome創建不必要的復合層,提升渲染性能,移動端優化效果尤為明顯。
參考: