CSS3動畫應用很廣,尤其是在H5項目中妆绞,炫酷的交互效果可以給產(chǎn)品帶來更好的體驗,更能吸引用戶枫攀。然而在應用的時候括饶,很多Web前端童鞋可能忽略了一點,就是其性能来涨;不管你是用純CSS3寫的動畫图焰,還是結(jié)合jQuery,性能很重要蹦掐。
網(wǎng)絡(luò)上有很多關(guān)于“CSS3動畫的性能優(yōu)化”的文章技羔,各抒己見,總而言之卧抗,初衷基本一樣藤滥。今天我主要針對一些比較優(yōu)秀的文章和自己的一些見解,總結(jié)一下H5頁面中CSS3動畫的性能優(yōu)化颗味。
在CSS3動畫制作過程中超陆,提升移動端CSS3動畫體驗的主要方法大概有幾點:
1、盡可能多的利用硬件能力,如使用3D變形來開啟GPU加速:
比如代碼:
-webkit-transform:?translate3d(0,?0,?0);
-moz-transform:?translate3d(0,?0,?0);
-ms-transform:?translate3d(0,?0,?0);
transform:?translate3d(0,?0,?0);
一個元素通過translate3d右移500px的動畫流暢度會明顯優(yōu)于使用left屬性时呀;原因:CSS動畫屬性會觸發(fā)整個頁面的重排relayout张漂、重繪repaint、重組recompositePaint通常是其中最花費性能的谨娜,盡可能避免使用觸發(fā)paint的CSS動畫屬性航攒,這也是為什么我們推薦在CSS動畫中使用webkit-transform: translateX(3em)的方案代替使用left: 3em,因為left會額外觸發(fā)layout與paint趴梢,而webkit-transform只觸發(fā)整個頁面composite(這也是為什么推薦在CSS動畫中使用webkit-transform: translateX(500px)的方案代替使用left: 500px)漠畜;
如動畫過程有閃爍(通常發(fā)生在動畫開始的時候),可以嘗試下面的Hack:
-webkit-backface-visibility:?hidden;
-moz-backface-visibility:?hidden;
-ms-backface-visibility:?hidden;
backface-visibility:?hidden;
-webkit-perspective:?1000;
-moz-perspective:?1000;
-ms-perspective:?1000;
perspective:?1000;
2坞靶、盡可能少的使用box-shadows與gradients
box-shadows與gradients往往都是頁面的性能殺手憔狞,尤其是在一個元素同時都使用了它們.
盡可能的讓動畫元素不在文檔流中,以減少重排
position:?fixed;
position:?absolute;
我們一起來看下CSS3動畫其中一些屬性性能消耗圖:
性能消耗圖彰阴,由此可見最受歡飲和性能最好的莫過于transform和opacity了瘾敢。
以上只是總結(jié)了2點關(guān)于性能優(yōu)化,后來參閱了一些其他的文章和自己的研究發(fā)現(xiàn):現(xiàn)代瀏覽器在使用CSS3動畫時尿这,以下四種情形繪制的效率較高(包含了以上2種)簇抵。
*改變位置*改變大小*旋轉(zhuǎn)*改變透明度
我們一起來學習下。
層射众?重繪碟摆?回流和重布局?圖層重組叨橱?
首先要了解CSS的圖層的概念(Chrome瀏覽器)
瀏覽器在渲染一個頁面時典蜕,會將頁面分為很多個圖層,圖層有大有小雏逾,每個圖層上有一個或多個節(jié)點嘉裤。在渲染DOM的時候,瀏覽器所做的工作實際上是:1.獲取DOM后分割為多個圖層2.對每個圖層的節(jié)點計算樣式結(jié)果(Recalculate style--樣式重計算)3.為每個節(jié)點生成圖形和位置(Layout--回流和重布局)4.將每個節(jié)點繪制填充到圖層位圖中(Paint Setup和Paint--重繪)5.圖層作為紋理上傳至GPU6.符合多個圖層到頁面上生成最終屏幕圖像(Composite Layers--圖層重組)
Chrome中滿足以下任意情況就會創(chuàng)建圖層:* 3D或透視變換(perspective transform)CSS屬性*使用加速視頻解碼的節(jié)點*擁有3D(WebGL)上下文或加速的2D上下文的節(jié)點*混合插件(如Flash)*對自己的opacity做CSS動畫或使用一個動畫webkit變換的元素*擁有加速CSS過濾器的元素*元素有一個包含復合層的后代節(jié)點(一個元素擁有一個子元素栖博,該子元素在自己的層里)*元素有一個z-index較低且包含一個復合層的兄弟元素(換句話說就是該元素在復合層上面渲染)
需要注意的是屑宠,如果圖層中某個元素需要重繪,那么整個圖層都需要重繪仇让。比如一個圖層包含很多節(jié)點典奉,其中有個gif圖,gif圖的每一幀丧叽,都會重回整個圖層的其他節(jié)點卫玖,然后生成最終的圖層位圖。所以這需要通過特殊的方式來強制gif圖屬于自己一個圖層(translateZ(0)或者translate3d(0,0,0))踊淳,CSS3的動畫也是一樣(好在絕大部分情況瀏覽器自己會為CSS3動畫的節(jié)點創(chuàng)建圖層)
層和CSS動畫
簡化一下上述過程假瞬,每一幀動畫瀏覽器可能需要做如下工作:1.計算需要被加載到節(jié)點上的樣式結(jié)果(Recalculate style--樣式重計算)2.為每個節(jié)點生成圖形和位置(Layout--回流和重布局)3.將每個節(jié)點填充到圖層中(Paint Setup和Paint--重繪)4.組合圖層到頁面上(Composite Layers--圖層重組)
如果我們需要使得動畫的性能提高陕靠,需要做的就是減少瀏覽器在動畫運行時所需要做的工作。最好的情況是脱茉,改變的屬性僅僅印象圖層的組合剪芥,變換(transform)和透明度(opacity)就屬于這種情況
現(xiàn)代瀏覽器如Chrome,F(xiàn)irefox琴许,Safari和Opera都對變換和透明度采用硬件加速税肪,但IE10+不是很確定是否硬件加速
觸發(fā)重布局的屬性
有些節(jié)點,當你改變他時榜田,會需要重新布局(這也意味著需要重新計算其他被影響的節(jié)點的位置和大幸嫘帧)。這種情況下箭券,被影響的DOM樹越大(可見節(jié)點)净捅,重繪所需要的時間就會越長,而渲染一幀動畫的時間也相應變長辩块。所以需要盡力避免這些屬性
一些常用的改變時會觸發(fā)重布局的屬性:盒子模型相關(guān)屬性會觸發(fā)重布局:* width* height* padding* margin* display* border-width* border* min-height
定位屬性及浮動也會觸發(fā)重布局:* top* bottom* left* right* position* float* clear
改變節(jié)點內(nèi)部文字結(jié)構(gòu)也會觸發(fā)重布局:* text-align* overflow-y* font-weight* overflow* font-family* line-height* vertival-align* white-space* font-size
這么多常用屬性都會觸發(fā)重布局灸叼,可以看到,他們的特點就是可能修改整個節(jié)點的大小或位置庆捺,所以會觸發(fā)重布局
別使用CSS類名做狀態(tài)標記
如果在網(wǎng)頁中使用CSS的類來對節(jié)點做狀態(tài)標記,當這些節(jié)點的狀態(tài)標記類修改時屁魏,將會觸發(fā)節(jié)點的重繪和重布局滔以。所以在節(jié)點上使用CSS類來做狀態(tài)比較是代價很昂貴的
觸發(fā)重繪的屬性
修改時只觸發(fā)重繪的屬性有:* color* border-style* border-radius* visibility* text-decoration* background* background-image* background-position* background-repeat* background-size* outline-color* outline* outline-style* outline-width* box-shadow
這樣可以看到,這些屬性都不會修改節(jié)點的大小和位置氓拼,自然不會觸發(fā)重布局你画,但是節(jié)點內(nèi)部的渲染效果進行了改變,所以只需要重繪就可以了
手機就算重繪也很慢
在重繪時桃漾,這些節(jié)點會被加載到GPU中進行重繪坏匪,這對移動設(shè)備如手機的影響還是很大的。因為CPU不如臺式機或筆記本電腦撬统,所以繪畫巫妖的時間更長适滓。而且CPU與GPU之間的有較大的帶寬限制,所以紋理的上傳需要一定時間
觸發(fā)圖層重組的屬性
透明度竟然不會觸發(fā)重繪恋追?
需要注意的是凭迹,上面那些觸發(fā)重繪的屬性里面沒有opacity(透明度),很奇怪不是嗎苦囱?實際上透明度的改變后嗅绸,GPU在繪畫時只是簡單的降低之前已經(jīng)畫好的紋理的alpha值來達到效果,并不需要整體的重繪撕彤。不過這個前提是這個被修改opacity本身必須是一個圖層鱼鸠,如果圖層下還有其他節(jié)點,GPU也會將他們透明化
強迫瀏覽器創(chuàng)建圖層
在Blink和WebKit的瀏覽器中,一當一個節(jié)點被設(shè)定了透明度的相關(guān)過渡效果或動畫時蚀狰,瀏覽器會將其作為一個單獨的圖層愉昆,但很多開發(fā)者使用translateZ(0)或者translate3d(0,0,0)去使瀏覽器創(chuàng)建圖層。這種方式可以消除在動畫開始之前的圖層創(chuàng)建時間造锅,使得動畫盡快開始(創(chuàng)建圖層和繪制圖層還是比較慢的)撼唾,而且不會隨著抗鋸齒而導出突變。不過這種方法需要節(jié)制哥蔚,否則會因為創(chuàng)建過多的圖層導致崩潰
Chrome中的抗鋸齒
Chrome中倒谷,非根圖層以及透明圖層使用grayscale antialiasing而不是subpixel antialiasing,如果抗鋸齒方法變化糙箍,這個效果將會非常顯著渤愁。如果你打算預處理一個節(jié)點而不打算等到動畫開始,可以通過這種強迫瀏覽器創(chuàng)建圖層的方式進行深夯。
transform變換是你的選擇
我們通過節(jié)點的transform可以修改節(jié)點的位置抖格、旋轉(zhuǎn)、大小等咕晋。我們平常會使用left和top屬性來修改節(jié)點的位置雹拄,但正如上面所述,left和top會觸發(fā)重布局掌呜,修改時的代價相當大滓玖。取而代之的更好方法是使用translate,這個不會觸發(fā)重布局质蕉。
JS動畫和CSS3動畫的比較
我們經(jīng)常面臨一個抉擇:是使用JavaScript的動畫還是使用CSS的動畫势篡,下面將對比一下這兩種方式。
JS動畫
缺點:JavaScript在瀏覽器的主線程中運行模暗,而其中還有很多其他需要運行的JavaScript禁悠、樣式計算、布局兑宇、繪制等對其干擾碍侦。這也就導致了線程可能出現(xiàn)阻塞,從而造成丟幀的情況顾孽。
優(yōu)點:JavaScript的動畫與CSS預先定義好的動畫不同祝钢,可以在其動畫過程中對其進行控制:開始、暫停若厚、回放拦英、中止、取消都是可以做到的测秸。而且一些動畫效果疤估,比如視差滾動效果灾常,只有JavaScript能夠完成。
CSS動畫
缺點:缺乏強大的控制能力铃拇。而且很難以有意義的方式結(jié)合到一起钞瀑,使得動畫變得復雜且易于出問題。優(yōu)點:瀏覽器可以對動畫進行優(yōu)化慷荔。它必要時可以創(chuàng)建圖層雕什,然后在主線程之外運行。
前瞻
Google目前正在探究通過JS的多線程(Web Workers)來提供更好的動畫效果显晶,而不會觸發(fā)重布局及樣式重計算贷岸。
結(jié)論
動畫給予了頁面豐富的視覺體驗。我們應該盡力避免使用會觸發(fā)重布局和重繪的屬性磷雇,以免失幀偿警。最好提前申明動畫,這樣能讓瀏覽器提前對動畫進行優(yōu)化唯笙。由于GPU的參與螟蒸,現(xiàn)在用來做動畫的最好屬性是如下幾個:* opacity* translate* rotate* scale
也許會有一些新的方式使得可以使用JavaScript做出更好的沒有限制的動畫,而且不用擔心主線程的阻塞問題崩掘。但在那之前七嫌,還是好好考慮下如何做出流暢的動畫吧。
OK苞慢,CSS3動畫的性能優(yōu)化抄瑟,大概的內(nèi)容就是這么多,其實這些遠遠不夠枉疼,更多的還得我們自己去研究和學習。
來源:Web前端之家
原文標題:關(guān)于H5頁面中CSS3動畫的性能優(yōu)化
=