對于頁面,我們經常有CSS對網頁進行呈現樣式效果,這就涉及到了頁面的重繪和重排
重繪(repaints)與重排(reflows,也稱回流)。
首先來了解一下頁面的呈現流程,頁面是如何將HTML和CSS結合等顯示在瀏覽器上的
步驟:
1 瀏覽器將HTML代碼解析成一個DOM樹,HTML中的每一個標簽都對應這個DOM樹中的一個節點,根節點就是我們常用的document對象,DOM樹包含了HTML代碼中的所有標簽,當然注釋掉的不算,包括了display:none隱藏的標簽,JS動態添加的也包括了
2 瀏覽器將所有的樣式(定義的CSS和用戶代理的)解析成樣式結構體,解析過程中會去掉瀏覽器不能識別的樣式,比如IE去掉了-moz開頭的樣式(FF對應的前綴),FF去掉_開頭的樣式(IE6的樣式寫法,可以見css hack一文)
3 DOM樹和樣式結構體組合構建一個Render Tree,稱為呈現樹,這個Render Tree結構類似于DOM樹,但是它能識別樣式,每一個節點node都有自己的樣式style,但是此時Render Tree就不會包括那些隱藏的節點了(如display:none的節點和head節點),因為這些節點不呈現,也不影響呈現。但是visibility:hidden還是會在呈現樹上,因為其僅僅是視覺上的隱藏,會影響布局,占有空間,而根據CSS2的標準,每一個Render Tree的節點都稱為Box,符合盒子模型,擁有填充,邊距,邊框,位置的盒子
4 構建呈現樹完成后,瀏覽器就根據其來繪制頁面了。
回流和重繪
1. 當render tree中的一部分(或全部)因為元素的規模尺寸,布局,隱藏等改變而需要重新構建。這就稱為回流(reflow)。每個頁面至少需要一次回流,就是在頁面第一次加載的時候。在回流的時候,瀏覽器會使渲染樹中受到影響的部分失效,并重新構造這部分渲染樹,完成回流后,瀏覽器會重新繪制受影響的部分到屏幕中,該過程成為重繪。
2. 當render tree中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀,風格,而不會影響布局的,比如background-color。則就叫稱為重繪。
注意:回流必將引起重繪,而重繪不一定會引起回流。
回流何時發生:
當頁面布局和幾何屬性改變時就需要回流。下述情況會發生瀏覽器回流:
1、添加或者刪除可見的DOM元素;
2、元素位置改變;
3、元素尺寸改變——邊距、填充、邊框、寬度和高度
4、內容改變——比如文本改變或者圖片大小改變而引起的計算值寬度和高度改變;
5、頁面渲染初始化;
6、瀏覽器窗口尺寸改寸改變——resize事件發生時;
影響回流重繪的例子:
說到這里大家都知道回流比重繪的代價要更高,回流的花銷跟render tree有多少節點需要重新構建有關系,假設你直接操作body,比如在body最前面插入1個元素,會導致整個render tree回流,這樣代價當然會比較高,但如果是指body后面插入1個元素,則不會影響前面元素的回流
聰明的瀏覽器
很多瀏覽器會優化一些操作,瀏覽器會維護一個隊列,把所有會引起回流、重繪的操作放入隊列中,等隊列的操作達到一定的數量或者到了一定的時間間隔,瀏覽器會flush隊列,進行一個批處理,這樣就讓多次的回流重繪變成一次回流重繪
但是有時候我們寫的一些代碼可能會強制瀏覽器提前flush隊列,這樣瀏覽器的優化可能就起不到作用了。當你請求向瀏覽器請求一些 style信息的時候,就會讓瀏覽器flush隊列,比如:
1. offsetTop, offsetLeft, offsetWidth, offsetHeight
2. scrollTop/Left/Width/Height
3. clientTop/Left/Width/Height
4. width,height
5. 請求了getComputedStyle(), 或者 IE的 currentStyle
當你請求上面的一些屬性的時候,瀏覽器為了給你最精確的值,需要flush隊列,因為隊列中可能會有影響到這些值的操作。即使你獲取元素的布局和樣式信息跟最近發生或改變的布局信息無關,瀏覽器都會強行刷新渲染隊列。
如何減少回流、重繪
減少回流、重繪其實就是需要減少對render tree的操作(合并多次多DOM和樣式的修改),并減少對一些style信息的請求,盡量利用好瀏覽器的優化策略。具體方法有:
1. 直接改變className,如果動態改變樣式,則使用cssText(考慮沒有優化的瀏覽器)
2. 讓要操作的元素進行”離線處理”,處理完后一起更新
a) 使用DocumentFragment進行緩存操作,引發一次回流和重繪;
b) 使用display:none技術,只引發兩次回流和重繪;
c) 使用cloneNode(true or false) 和 replaceChild 技術,引發一次回流和重繪;
3.不要經常訪問會引起瀏覽器flush隊列的屬性,如果你確實要訪問,利用緩存
4. 讓元素脫離動畫流,減少回流的Render Tree的規模
來源于:http://www.css88.com/archives/4996