本文翻譯自html5rock上的文章,文章英文原版地址在最後給出。
文中的Paints我翻譯成渲染繪製,我自己是這麼理解。
開始
繪製(渲染)一個網站或者一個應用的元素對瀏覽器來說開銷是很大的,它會對執行時的效率產生負面影響,在這篇文章中我們將快速的過一遍,哪些情況會導致導致繪製事件在瀏覽器中產生,以及如何在你今後的工作中儘量避免沒必要的繪製。
繪製(渲染):一場超快的旅行
瀏覽器的主要任務之一就是將DOM和CSS轉換成畫素並繪製到屏目上,這是一系列複雜的處理過程。瀏覽器先讀取HTML標籤並由此建立DOM樹,它對CSS也是進行了類似的工作,讀取CSS並建立CSSOM樹,然後將兩者合併,最終我們就可以根據合併後的結構渲染成畫素到屏目了
繪製過程本身就挺有趣。在Chrome瀏覽器中,合併後的DOM樹與CSS樹被一款名叫Skia的軟體進行柵格化。如果你曾使用過CANVAS的API,那麼你會覺得它們的API非常相似。
不光是moveTo, lineTo等這些API,另外的一些高階API也一樣非常相似。本質上來講,所有需要被繪製的元素都將被提取到能被Skia執行的集合中,執行後輸出的是一堆點陣圖。這些點陣圖將被上傳到GPU中,GPU將幫他們組合在一起並最終輸出到屏目上。
Skia的工作量是直接受你在元素上所應用的樣式引響的。如果你在元素應用的樣式演算法很複雜那麼,會大大加重Skia的工作。你可以參考這篇文章article on how CSS affects page render weight,以更深的理解CSS如何影響頁面渲染。
總而言之,繪製工作費時間,如果我們不減少繪製,那麼可能會掉偵。使用者可能會注意到掉幀,看起來會閃一下。這對於我們的APP上來說是從根本上傷害了使用者體驗。我們不希望看到這樣的結果吧,so讓我們來看看哪些東西會產生必要的繪製(渲染)工作,以及我們能對這些做些啥優化。
Scrolling(滾動)
無論你是往上還是往下滾動,內容在顯示到屏目上之前瀏覽器都需要進行重繪。如果一切順利的話,可能產生重繪的區域會是很小一塊,但是即使是很小一塊,那一小塊元素可能就是應用了複雜的CSS樣式。所以不會因為繪製的區域小而繪製的速度會快。
為了看清哪些區域被重繪了,你可以使用Chrome中自帶的除錯工具,點選右上角的設定按鈕,選中 “Show Paint Rectangles”後,在你的頁面中做一些簡單的互動,你便會看到一些會閃動的矩形框,那就是重繪的區域了。
滾動的效能表現,是你網站成功的關鍵。使用者真的會關心你的站點或應用滾動的是不是順暢,他們可不會喜歡滾動的不流暢的網站。我們在滾動時保證輕量的繪製工作,因此而得到的一個好處就是使用者看不到閃動或掉幀這類事情了。
我之前已經寫過一篇文章是關於滾動效能的,如果你想了解更我,可以參考這篇文章 article on scrolling performance
Interactions(互動)
互動是另一個產生繪製工作的原因,如:hovers, click,touches drags無論使用者執行了其中的哪一樣操作都會引發繪製或重繪。讓我們以hover舉個栗子,當hover某個元素時,Chrome不得不重繪那個被hover影響的元素。如果滾動時有一個很大很複雜的重繪工作,那麼你將會看到繪製幀頻的下降。
大家都想要好的、流暢的互動動畫,這我們又得關心一下動畫樣式在變化時的花費時間及效能成本
An unfortunate combination(不幸的組合)
當我滾動的同時移動滑鼠時會發生什麼 ?在無意中是完全有可能觸發昂貴的重繪開銷的,這將導致我的幀頻率小於16.7ms(我們應該保持在每秒60幀的頻率)。我已經寫了一個demo來更直觀的表達我所說的情況created a demo 希望你在滾動的同時移動滑鼠能看到hover效果。但是讓我們看看Chrome除錯工具告訴了我們什麼
在上圖中你可以看到,當我在某一個塊元素上(blocks)上hover時除錯工具已捕獲了繪製工作。為了看效果,我在demo中瘋狂的加重了樣式效果(縮放,陰間等動畫效果)。這導致幀頻逼近或偶爾間超過了幀頻的臨界值。最後我想要的是減少不必要的繪製工作,尤其是在滾動時。
我們如何實現呢,實現其實很簡單,技巧是新增一個scroll回撥handler處理函式,在這個函式內禁止hover效果,同時設定一個計時器,用以恢復hover效果。這意謂著我們保證在滾動時禁止一些開銷昂貴的互動效果,並且在停止滾動足夠的時間後恢復那些效果
實際應用時注意!
改變此項會影響你應用程式使用者體驗,所以明智的對待它,延時恢復效果要在你和的團隊能接受的時間範圍內
這是對應的程式碼
// Used to track the enabling of hover effects var enableTimer = 0; /* * Listen for a scroll and use that to remove * the possibility of hover effects */ window.addEventListener('scroll', function() { clearTimeout(enableTimer); removeHoverClass(); // enable after 1 second, choose your own value here! enableTimer = setTimeout(addHoverClass, 1000); }, false); /** * Removes the hover class from the body. Hover styles * are reliant on this class being present */ function removeHoverClass() { document.body.classList.remove('hover'); } /** * Adds the hover class to the body. Hover styles * are reliant on this class being present */ function addHoverClass() { document.body.classList.add('hover'); }
如你所見,我們用了一個class來決定hover效果是否被允許使用,下面就是這個class的css表示式
/* Expect the hover class to be on the body before doing any hover effects */ .hover .block:hover { … }
這就是所有的內容了
Conclusion(結束語)
渲染的效能表現對於使用者是否喜歡你的應用至關重要,你需要的是儘量保證繪製工作量保持在16ms幀頻率以下,為了幫助實現這一目標,你得使調式工具一直貫穿於你的開發過程中,確保幀頻保持在正常範圍內,並隨時修復上升的幀頻。
被忽略的互動過程,特別是重試繪製元素,是渲染效能的殺手,正如你所見,我們可以用一些簡單的程式碼解決掉這些問題。
看一看你的站點和應用,能不能做一些渲染繪製上面的優化
本文翻譯自:
http://www.html5rocks.com/en/tutorials/speed/unnecessary-paints/
我英文水平有限,湊合著翻,全當自我學習歡迎交流學習
========================================================
轉載處請註明:部落格園(王二狗)willian12345@126.com