頁面的重繪與回流及優化

2022-02-09 04:52:45 字數 3844 閱讀 6456

首先要清楚頁面呈現的具體過程:

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),理解頁面元素為乙個具有填充、邊距、邊框和位置的盒子。

回流與重繪

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

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

注意:回流必將引起重繪,而重繪不一定會引起回流。我們需要明白,頁面若發生回流則需要付出很高的代價。

回流何時發生:

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

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

2、元素位置改變;

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

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

5、頁面渲染初始化;

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

聰明的瀏覽器

從上個例項**中可以看到幾行簡單的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資訊的請求,盡量利用好瀏覽器的優化策略。具體方法有:

1. 直接改變classname,如果動態改變樣式,則使用csstext(考慮沒有優化的瀏覽器)

// 不好的寫法

var left = 1;

var top = 1;

el.style.left = left + "px";

el.style.top = top + "px";

// 比較好的寫法

el.classname += " classname1";

// 比較好的寫法

el.style.csstext += ";

left: " + left + "px;

top: " + top + "px;";

2. 讓要操作的元素進行」離線處理」,處理完後一起更新

a) 使用documentfragment進行快取操作,引發一次回流和重繪;

//

不好的寫法(模式中所說的反模式)

varp, t;

p = document.createlement('p');

t = document.creattextnode('fist paragraph');

//將引起一次回流

p = document.createlement('p');

t = document.creattextnode('second paragraph');

//將再引起一次回流

//好的寫法

varp, t, frag;

frag =document.creatdocumentfragment();

p = document.createlement('p');

t = document.creattextnode('fist paragraph');

p = document.createlement('p');

t = document.creattextnode('second paragraph');

//相比前面的方法,這裡僅僅引起一次回流,倘若頁面裡有很多這樣的操作,利用文件隨便將會提公升很多

b) 使用display:none技術,只引發兩次回流和重繪; ( 只是減少重繪和回流的次數,display:none 是會引起重繪並回流,相對來說,visibility: hidden只會引起重繪

)c) 使用clonenode(true or false) 和 replacechild 技術,引發一次回流和重繪;

//

建立轉殖映象

var oldnode = document.getelementbyid('target'),

clone = oldnode.clonenode(true); //

深複製//

處理轉殖物件的操作....

//完成後

oldnode.parentnode.replacechild(clone,oldnode);

3.不要經常訪問會引起瀏覽器flush佇列的屬性,如果你確實要訪問,利用快取

//

bad way

for(迴圈) //

這樣寫好點

var left =el.offsetleft,

top =el.offsettop,

s =el.style;

for(迴圈)

4. 讓元素脫離動畫流,減少回流的render tree的規模

本文有參考自也有自己的一些理解,若有不對歡迎拍磚

頁面的回流與重繪

在構建渲染樹的過程中,瀏覽器主要完成了一下工作 前邊通過構造渲染樹,我們將可見dom節點以及它對應的樣式結合起來,可是我們還需要計算他們在裝置視口 viewport 內的準確位置和大小,這個計算的階段就是回流。最終,我們通過構造渲染樹和回流階段,我們知道了哪些節點是可見的,以及可見節點的樣式和具體的...

頁面的重繪與回流

上次在面試中,面試官問了我乙個關於頁面重繪和回流的問題,我解釋的不怎麼好。今天把它整理了一下,又參考了一些其他的文章。參考文章 頁面載入過程 1 瀏覽器將獲取到的html 解析成乙個dom樹,html中的每乙個標籤都是dom樹中的乙個節點,根節點就是document。dom樹中包含了所有的html標...

web頁面的回流和重繪

什麼是回流?回流也叫重排 reflow 當頁面中的元素發生影響布局的變化,比如 改變寬高,修改顯示影藏。頁面需要重新布局,就會觸發重排。簡單的說就是,頁面布局改變,就會觸發重排。什麼是重繪 repaint 頁面中的元素樣式發生改變注意 每個頁面只要會發生一次重排和重繪。重排一定會觸發重繪前端效能優化...