1. 程式人生 > >html頁面重繪和迴流以及優化

html頁面重繪和迴流以及優化

在討論頁面重繪、迴流之前。需要對頁面的呈現流程有些瞭解,頁面是怎麼把html結合css等顯示到瀏覽器上的,下面的流程圖顯示了瀏覽器對頁面的呈現的處理流程。可能不同的瀏覽器略微會有些不同。但基本上都是類似的。
在這裡插入圖片描述
1.瀏覽器把獲取到的HTML程式碼解析成1個DOM樹,HTML中的每個tag都是DOM樹中的1個節點,根節點就是我們常用的document物件。DOM樹裡包含了所有HTML標籤,包括display:none隱藏,還有用JS動態新增的元素等。

2.瀏覽器把所有樣式(使用者定義的CSS和使用者代理)解析成樣式結構體,在解析的過程中會去掉瀏覽器不能識別的樣式,比如IE會去掉-moz開頭的樣式,而FF會去掉_開頭的樣式。

3.DOM Tree 和樣式結構體組合後構建render tree, render tree類似於DOM tree,但區別很大,render tree能識別樣式,render tree中每個NODE都有自己的style,而且 render tree不包含隱藏的節點 (比如display:none的節點,還有head節點),因為這些節點不會用於呈現,而且不會影響呈現的,所以就不會包含到 render tree中。注意 visibility:hidden隱藏的元素還是會包含到 render tree中的,因為visibility:hidden 會影響佈局(layout),會佔有空間。根據CSS2的標準,render tree中的每個節點都稱為Box (Box dimensions),理解頁面元素為一個具有填充、邊距、邊框和位置的盒子。

4.一旦render tree構建完畢後,瀏覽器就可以根據render tree來繪製頁面了。

迴流與重繪

1.當render tree中的一部分(或全部)因為元素的規模尺寸,佈局,隱藏等改變而需要重新構建。這就稱為迴流(reflow)。每個頁面至少需要一次迴流,就是在頁面第一次載入的時候。在迴流的時候,瀏覽器會使渲染樹中受到影響的部分失效,並重新構造這部分渲染樹,完成迴流後,瀏覽器會重新繪製受影響的部分到螢幕中,該過程成為重繪。

2.當render tree中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀,風格,而不會影響佈局的,比如background-color。則就叫稱為重繪。

注意:迴流必將引起重繪,而重繪不一定會引起迴流。

迴流何時發生:

當頁面佈局和幾何屬性改變時就需要回流。下述情況會發生瀏覽器迴流:

1、新增或者刪除可見的DOM元素;

2、元素位置改變;

3、元素尺寸改變——邊距、填充、邊框、寬度和高度

4、內容改變——比如文字改變或者圖片大小改變而引起的計算值寬度和高度改變;

5、頁面渲染初始化;

6、瀏覽器視窗尺寸改變——resize事件發生時;

讓我們看看下面的程式碼是如何影響迴流和重繪的:
js 程式碼:

var s = document.body.style;
s.padding = "2px"; // 迴流+重繪
s.border = "1px solid red"; // 再一次 迴流+重繪
s.color = "blue"; // 再一次重繪
s.backgroundColor = "#ccc"; // 再一次 重繪
s.fontSize = "14px"; // 再一次 迴流+重繪
// 新增node,再一次 迴流+重繪
document.body.appendChild(document.createTextNode('abc!'));

說到這裡大家都知道迴流比重繪的代價要更高,迴流的花銷跟render tree有多少節點需要重新構建有關係,假設你直接操作body,比如在body最前面插入1個元素,會導致整個render tree迴流,這樣代價當然會比較高,但如果是指body後面插入1個元素,則不會影響前面元素的迴流。

聰明的瀏覽器

從上個例項程式碼中可以看到幾行簡單的JS程式碼就引起了6次左右的迴流、重繪。而且我們也知道迴流的花銷也不小,如果每句JS操作都去迴流重繪的話,瀏覽器可能就會受不了。所以很多瀏覽器都會優化這些操作,瀏覽器會維護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資訊的請求,儘量利用好瀏覽器的優化策略。