常聽人說:html
移動端要想動畫性能流暢,應該使用3d硬件加速前端
最近深刻了解了一些瀏覽器內核的細節,感受這裏面其實有坑啊。。。html5
事情要從最近看的《WebKit技術內幕》提及,第二章介紹了網頁的結構,其中提到了Webkit硬件加速的方式,會把須要渲染的元素放到特定的『Composited Layer』中,在chrome的控制檯能夠這樣開啓:git
選擇『Show composited layer borders』之後,就能看到有動畫3d變換的元素會被一個黃色的邊框圈起來,表示放到了一個新的『複合層(composited layer)』中渲染,大概長這個樣子:github
藍色的細線是瀏覽器渲染時候的『瓦片』,瀏覽器繪製頁面的時候只會繪製可視區域必定範圍內的瓦片,以節省性能開銷,而黃色的邊框框起來的,就表明了這個元素被放到特殊的複合層中渲染,跟主文檔不在一個層中web
而後我以爲這個視圖挺有意思的,就拿來看了一下國內某項目,不看不知道,一看被嚇尿:chrome
這個項目何時搞成全部元素都用3d加速了?!後端
仔細排查了這些被框出來的元素,徹底沒有任何須要複合層渲染的跡象,我真是嗶了狗了。。。我開始一個個刪除元素,簡化代碼,很快就發現,原來罪魁禍首在這裏:瀏覽器
頭部的那個輪播動畫元素的存在竟然會致使下面全部相對和絕對定位的元素都被放到複合層中。。。markdown
查了一些 資料:
層建立標準
什麼狀況下能使元素得到本身的層?雖然 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,如今看來問題就在這裏了!
因而乎我寫了一個頁面,讓你們看看這東西到底有多大威力:
我在上面這個頁面中放置了一個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技術內幕》這本書。瀏覽器內核之於前端工程師,就如同操做系統之於後端工程師,畢竟是咱們程序運行的宿主環境,多瞭解一些,不少問題容易想通。
若是有人讓你推薦前端技術書,請讓他看這個列表 ->《 經典前端技術書籍》 1 贊 1 收藏 評論