你真的了解CSS3硬件加速吗?
常聽人說:
移動端要想動畫性能流暢,應該使用3d硬件加速
最近深入了解了一些瀏覽器內核的細節,感覺這里面其實有坑啊。。。
事情要從最近看的《WebKit技術內幕》說起,第二章介紹了網頁的結構,其中提到了Webkit硬件加速的方式,會把需要渲染的元素放到特定的『Composited Layer』中,在chrome的控制臺可以這樣開啟:
選擇『Show composited layer borders』以后,就能看到有動畫3d變換的元素會被一個黃色的邊框圈起來,表示放到了一個新的『復合層(composited layer)』中渲染,大概長這個樣子:
藍色的細線是瀏覽器渲染時候的『瓦片』,瀏覽器繪制頁面的時候只會繪制可視區域一定范圍內的瓦片,以節省性能開銷,而黃色的邊框框起來的,就代表了這個元素被放到特殊的復合層中渲染,跟主文檔不在一個層中
然后我覺得這個視圖挺有意思的,就拿來看了一下國內某項目,不看不知道,一看被嚇尿:
這個項目什么時候搞成所有元素都用3d加速了?!
仔細排查了這些被框出來的元素,完全沒有任何需要復合層渲染的跡象,我真是嗶了狗了。。。我開始一個個刪除元素,簡化代碼,很快就發現,原來罪魁禍首在這里:
頭部的那個輪播動畫元素的存在居然會導致下面所有相對和絕對定位的元素都被放到復合層中。。。
查了一些?資料:
層創建標準
什么情況下能使元素獲得自己的層?雖然 Chrome 的啟發式方法(heuristic)隨著時間在不斷發展進步,但是從目前來說,滿足以下任意情況便會創建層:
- 3D 或透視變換(perspective transform) CSS 屬性
- 使用加速視頻解碼的 元素
- 擁有 3D (WebGL) 上下文或加速的 2D 上下文的 元素
- 混合插件(如 Flash)
- 對自己的 opacity 做 CSS 動畫或使用一個動畫 webkit 變換的元素
- 擁有加速 CSS 過濾器的元素
- 元素有一個包含復合層的后代節點(換句話說,就是一個元素擁有一個子元素,該子元素在自己的層里)
- 元素有一個 z-index 較低且包含一個復合層的兄弟元素(換句話說就是該元素在復合層上面渲染)
主要是最后一條,我覺得它的中文翻譯不是很準確,原文其實是:
Element has a sibling with a lower z-index which has a compositing layer (in other words the it’s rendered on top of a composited layer)
這句話的意思是,如果有一個元素,它的兄弟元素在復合層中渲染,而這個兄弟元素的z-index比較小,那么這個元素(不管是不是應用了硬件加速樣式)也會被放到復合層中。
最可怕的是,瀏覽器有可能給復合層之后的所有相對或絕對定位的元素都創建一個復合層來渲染,于是就有了上面那個項目截圖的那種效果。之前一直奇怪為什么這個頁面滾動很卡,明明沒有多少DOM,現在看來問題就在這里了!
于是乎我寫了一個頁面,讓大家看看這東西到底有多大威力:
http://fouber.github.io/test/layer/
我在上面這個頁面中放置了一個h1標題,應用了translate3d動畫,使得它被放到composited layer中渲染,然后在這個元素后面創建了2000個list,每個list中都有一個圖片,一個標題和一個日期顯示,其中圖片和日期顯示是絕對定位,父容器li是相對定位,然后,各位可以按照前述的說明打開chrome的『show composited layer borders』選項看看這個頁面的內容復合層分布:
就是這個鳥樣子,很難想象,這樣的頁面滾動起來會卡成什么樣。我用的是mac機器,快速拖動滾動條chrome已經非常吃力了,然后我寫了一個簡單的滾動條移動操作:
setInterval('document.body.scrollTop++', 0);
然后用timeline抓一下頁面性能:
一次『Composite Layers』的計算居然要?96.206?ms?!!這還是在我的mac系統上哦,手機上真的會卡出翔。
我在頁面上放置了一個開關『為動畫元素設置z-index』,這個checkbox點擊之后,會用js給那個動畫的h1元素加?position:relative?和?z-index: 1?,這種做法的原理是人為提升動畫元素的z-index,讓瀏覽器知道這個元素的層排序,就不會很傻逼的把其他z-index比它高的元素也弄到復合層中了,看看這個效果:
僅僅給動畫元素設置一個高一些的z-index,就能解決這種無厘頭增加復合層的問題,略無語。。。搞定之后,再用滾動條移動函數抓一下頁面性能:
完全恢復正常了有木有!
大家可以用支持『硬件加速』的『安卓』手機瀏覽器測試上述頁面,給動畫元素加z-index前后的性能差距非常明顯。
不過也不是所有瀏覽器都有這個問題,我在mac上的Safari、firefox都沒有明顯差異,安卓手機上的QQ瀏覽器好像也正常,獵豹、UC、歐朋、webview等瀏覽器差距明顯,更多測試就靠大家來發現吧。
最后總結一下:
使用3D硬件加速提升動畫性能時,最好給元素增加一個z-index屬性,人為干擾復合層的排序,可以有效減少chrome創建不必要的復合層,提升渲染性能,移動端優化效果尤為明顯。
大家可以現在就排查一下這類問題,尤其是用了輪播、動畫loading的頁面,出現這問題很常見。另外推薦在追查性能問題的時候打開『show composited layer borders』選項,如果頁面有很多黃色的框肯定是不對的。
最后,再次推薦一下《Webkit技術內幕》這本書。瀏覽器內核之于前端工程師,就如同操作系統之于后端工程師,畢竟是我們程序運行的宿主環境,多了解一些,很多問題容易想通。
參考:V8社區
在Blink和WebKit的瀏覽器中,某個元素具有3D或透視變換(perspective transform)的CSS屬性,會讓瀏覽器創建單獨的圖層。
我們平常會使用left和top屬性來修改元素的位置,但left和top會觸發重布局,取而代之的更好方法是使用translate,這個不會觸發重布局。
解決瀏覽器渲染的性能問題時,首要目標就是要避免層的重繪和重排。
總結
以上是生活随笔為你收集整理的你真的了解CSS3硬件加速吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 氢氧化钠遇水会不会放热
- 下一篇: (四)CSS 规范