原文地址:http://www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-your-javascript-slow/
原作者:Nicole Sullivan
翻譯:張鑫旭
關於迴流(reflows)與重繪(repaints),我已經在twitter和delicious上發佈,但是並沒有在演講中提到或是以文章形式發佈。
第一次讓我開始思考關於迴流(reflows)與重繪(repaints)的問題是在和ParisWeb上的Mr. Glazman做一個firey交換的時候。我可能有一些頑固,但是我確實聽了他的一些理論。Stoyan和我開始討論如何量化這個問題。
展望性能社區,除了一些典型的黑盒實驗外,需要與瀏覽器廠商有更多的合作。對於性能,瀏覽器製造者知道哪些是重要的,哪些是不相干的。Opera列出“reflow和repaint是減緩JavaScript的三大主要原因之一”一文,所以其肯定值得一看。// zxx: Firefox瀏覽器相關內容可以看這裏;Safari可以看這裏。
讓我們從一些背景資料開始,當一個元素的外觀的可見性visibility發生改變的時候,重繪(repaint)也隨之發生,但是不影響佈局。類似的例子包括:outline, visibility, or background color。根據Opera瀏覽器,重繪的代價是高昂的,因爲瀏覽器必須驗證DOM樹上其他節點元素的可見性。而回流更是性能的關鍵因爲其變化涉及到部分頁面(或是整個頁面)的佈局。一個元素的迴流導致了其所有子元素以及DOM中緊隨其後的祖先元素的隨後的迴流。
例如:
<body> <div class="error"> <h4>我的組件</h4> <p><strong>錯誤:</strong>錯誤的描述…</p> <h5>錯誤糾正</h5> <ol> <li>第一步</li> <li>第二步</li> </ol> </div> </body>
在上面的HTML片段中,對該段落(<p>標籤)迴流將會引發強烈的迴流,因爲它是一個子節點。這也導致了祖先的迴流(div.error和body – 視瀏覽器而定)。此外,h5和ol也會有簡單的迴流,因爲其在DOM中在迴流元素之後。就Opera而言,大部分的迴流將導致頁面的重新渲染。
Opera原文:Reflows are very expensive in terms of performance, and is one of the main causes of slow DOM scripts, especially on devices with low processing power, such as phones. In many cases, they are equivalent to laying out the entire page again.
既然它們對性能影響如此可怕,那什麼會導致迴流呢?
不幸的是,很多的東西,其中一些還與CSS的書寫特別相關。
- 調整窗口大小(Resizing the window)
- 改變字體(Changing the font)
- 增加或者移除樣式表(Adding or removing a stylesheet)
- 內容變化,比如用戶在input框中輸入文字(Content changes, such as a user typing text in
an input box) - 激活 CSS 僞類,比如 :hover (IE 中爲兄弟結點僞類的激活)(Activation of CSS pseudo classes such as :hover (in IE the activation of the pseudo class of a sibling))
- 操作 class 屬性(Manipulating the class attribute)
- 腳本操作 DOM(A script manipulating the DOM)
- 計算 offsetWidth 和 offsetHeight 屬性(Calculating offsetWidth and offsetHeight)
- 設置 style 屬性的值 (Setting a property of the style attribute)
Mozilla關於迴流的文章羅列了導致迴流的要點以及何時可以減少他們。
如何避免迴流或將它們對性能的影響降到最低?
注意:這裏我限定了自己只能討論CSS對迴流的影響,如果您是一位JavaScript程序員,我是推薦您讀一下我的reflow鏈接(zxx: 原作者收藏標記的一些關於reflow的一些文章或頁面鏈接),有一些非常好的東西,沒有直接關係到CSS。
- 如果想設定元素的樣式,通過改變元素的 class 名 (儘可能在 DOM 樹的最末端)(Change classes on the element you wish to style (as low in the dom tree as possible))
- 避免設置多項內聯樣式(Avoid setting multiple inline styles)
- 應用元素的動畫,使用 position 屬性的 fixed 值或 absolute 值(Apply animations to elements that are position fixed or absolute)
- 權衡平滑和速度(Trade smoothness for speed)
- 避免使用table佈局(Avoid tables for layout)
- 避免使用CSS的JavaScript表達式 (僅 IE 瀏覽器)(Avoid JavaScript expressions in the CSS (IE only))
儘可能在DOM樹的最末端改變class
避免設置多層內聯樣式
動畫效果應用到position屬性爲absolute或fixed的元素上
犧牲平滑度換取速度
避免使用table佈局
Jenny Donnelly, YUI 數據表格 widget的所有者,建議使用數據表格的固定佈局以便更有效的佈局算法,任何表格-佈局的值除了”auto”將引發一個固定佈局,根據CSS2.1規範,這將允許表格一行一行的呈遞。Quirksmode顯示,大部分的瀏覽器對錶格佈局屬性支持良好。
In this manner, the user agent can begin to lay out the table once the entire first row has been received. Cells in subsequent rows do not affect column widths. Any cell that has content that overflows uses the ‘overflow’ property to determine whether to clip the overflow content.
This algorithm may be inefficient since it requires the user agent to have access to all the content in the table before determining the final layout and may demand more than one pass.
避免使用CSS的JavaScript表達式
進一步的學習
Yahoo!出色的性能團隊做了一個實驗,以確定最佳的方法引入外部的樣式表文件。我們建議把鏈接標記放在頭部,儘管其比所有其他阻礙進一步渲染的方法慢一秒(6.3至7.3秒)。雖然逐步地渲染不可改變的(用戶討厭盯着一個空白屏幕),但它使我對下載組件和整體響應時間的渲染,重畫,迴流和CPU的顛簸造成的影響感到好奇。如果我們可以減少加載過程中的迴流個數我們可以奪回了失去的時間的十分之一(100毫秒)嗎?如果它是多達一半呢?
在SXSW我試圖說服史蒂夫的迴流是很重要的。我告訴他一個我已經做了很長一段時間的實驗,只是沒有時間。我希望有人能在我留下來的那個地方繼續(提示!提示!)。雖然加載頁面我想故意引發不同程度的迴流。這或許可以通過切換一個body(實驗)標籤的class名稱來改變body的最後一個child(沒有子節點)完成。比較這兩者情況,並增加每秒迴流的數目,我們可以關聯迴流反應時間。衡量JS反應對迴流的影響將會更難,因爲我們所做能夠引發迴流的事情都可能會影響實驗。
最後,量化影響的趣味只有那麼一點點,因爲瀏覽器廠商會告訴我們它的問題。或許更有趣的是把注意力集中在迴流的原因以及如何避免它們。這將需要更好的工具,所以我需要瀏覽器廠商和性能社區共同努力,使之成爲現實!
事實說話
也許你是一個視覺關注者,這些視頻通過很酷的方式將回流過程可視化展示出來。//zxx: youtube視頻,想看,需翻牆。
- http://www.youtube.com/watch?v=nJtBUHyNBxs
- http://www.youtube.com/watch?v=ZTnIxIA5KGw
- http://www.youtube.com/watch?v=dndeRnzkJDU
迴流消失的瘋狂
爲了改進性能,瀏覽器廠商可能限制迴流影響臨近的節點或者聯合其他幾個迴流形成一次大的改變,就如Mozilla的這篇文章中展示的。這可以提高性能,但有時也可能導致顯示問題。您可以使用我們所瞭解到的關於迴流的知識,在必要糾正相關顯示問題的時候觸發它們。
例如,我們改變圖片優化網站上的選項卡,http://smush.it,隨着選項卡的不同,內容區域的高度是不斷變化的,有時候,下面的投影會被留下,這是因爲內容區域上的父節點被切換而其容器可能沒有迴流,下面這張圖是模擬的,因爲這個bug很難用相機捕捉,任何試圖獲取操作都會導致迴流而糾正顯示。如果你自己發現類似的bug,移動背景圖片到下面切換的DOM元素上。
另外一個例子是動態添加列表項,當您將列表項從9個增加到10個或是從99個增加到100個,列表的數字將不會正確的排隊顯示,這在所有瀏覽器都是。當總數按數量的順序增加且瀏覽器不迴流兄弟節點時,隊列被打破。快速切換整個列表的顯示或是增加添加一個class類,即使沒有相關聯的樣式,也會導致迴流和正確的隊列顯示。
工具
最近有小部分工具產生了一些波瀾,Stoyan Stefanov和我已經一直在尋找好的方法來測量回流與重繪,這裏有一些(儘管比較早)。要當心,有的在我正確使用之前把瀏覽器給搞跛了。大部分情況下,你需要每晚安裝下最新的版本。
當Mozilla公開MozAfterPaint Firefox API時,互聯網界議論紛紛。
- 更新:Google的Lindsey Simon寫了個可以在任意瀏覽器下測試迴流時間的書籤工具。非常的贊,注意:所有的震動都是正常的。//zxx: 我測試此鏈接爲500錯誤
- John Resig寫了個書籤工具來可視化繪製事件。
- Kyle Scholz創建了一個工具用來在頁面加載之前可視化繪製事件
- Yoono的Alex創建了XUL分析工具
是否其他人見到過好的關於迴流評估的工具?請發送告知我。
還有其他一對不是直接用來處理迴流的工具。
- IE瀏覽器視覺往返分析儀(VRTA),因爲微軟起了個這麼有趣的名字,所以我們可能還真的會用它。
- 專爲WPF的性能分析工具
最後,我們需要一個跨瀏覽器的工具來量化並減少迴流和重繪。我希望性能社區能夠與瀏覽器廠商合作,使這一工具成爲現實。瀏覽器廠商已經告訴我們有一段時間了,這是我們未來需要看到的,希望在我們手中。