回流與重繪

2021-10-09 22:09:11 字數 3077 閱讀 1805

當我們對 dom 的修改引發了 dom 幾何尺寸的變化(比如修改元素的寬、高或隱藏元素等)時,瀏覽器需要重新計算元素的幾何屬性(其他元素的幾何屬性和位置也會因此受到影響),然後再將計算的結果繪製出來。這個過程就是回流(也叫重排)。

引發回流的操作:

1.修改dom元素。當乙個dom元素的幾何屬性發生變化時,所有和它相關的節點(比如父子節點、兄弟節點等)的幾何屬性都需要進行重新計算。

2.頁面首次渲染

3.瀏覽器視窗大小發生改變 

4.元素的尺寸和位置發生改變(width、height、padding、margin、left、top、border )等等

當我們對 dom 的修改導致了樣式的變化、卻並未影響其幾何屬性(比如修改了顏色或背景色)時,瀏覽器不需重新計算元素的幾何屬性、直接為該元素繪製新的樣式(跳過了上圖所示的回流環節)。這個過程叫做重繪。

一句話:回流必將引起重繪,重繪不一定會引起回流

如果每次 dom 操作都即時地反饋一次回流或重繪,那麼效能上來說是扛不住的。所以很多瀏覽器都會優化這些操作,於是它自己快取了乙個 flush 佇列,把所有會引起回流、重繪的操作放入這個佇列,待到佇列裡的任務多起來、或者達到了一定的時間間隔,或者「不得已」的時候,再將這些任務一口氣出隊。 這樣就會讓多次的回流、重繪變成一次回流重繪。

注意:佇列強制重新整理

因為有的時候我們需要精確獲取某些樣式資訊,例如:

offsettop, offsetleft, offsetwidth, offsetheight scrolltop/left/width/height clienttop/left/width/height width,height 請求了getcomputedstyle(), 或者 ie的 currentstyle 這個時候,瀏覽器為了反饋最精確的資訊,需要立即回流重繪一次,確保給到我們的資訊是準確的,所以可能導致 flush 佇列提前執行了。

css:

1、避免使用table布局。 2、盡可能在dom樹的最末端改變class。 3、避免設定多層內聯樣式。 4、將動畫效果應用到position屬性為absolute或fixed的元素上。 5、避免使用css表示式(例如:calc())。

js:

1、避免頻繁操作樣式,最好一次性重寫style屬性,或者將樣式列表定義為class並一次性更改class屬性。 2、避免頻繁操作dom,建立乙個documentfragment,在它上面應用所有dom操作,最後再把它新增到文件中。 3、也可以先為元素設定display: none,操作結束後再把它顯示出來。因為在display屬性為none的元素上進行的dom操作不會引發回流和重繪。 4、避免頻繁讀取會引發回流/重繪的屬性,如果確實需要多次使用,就用乙個變數快取起來。 5、對具有複雜動畫的元素使用絕對定位,使它脫離文件流,否則會引起父元素及後續元素頻繁回流。

有時我們想要通過多次計算得到乙個元素的布局位置,我們可能會這樣做:

這樣做,每次迴圈都需要獲取多次「敏感屬性」,是比較糟糕的。我們可以將其以 js 變數的形式快取起來,待計算完畢再提交給瀏覽器發出重計算請求:

// 快取offsetleft與offsettop的值

const el = document.getelementbyid('el')

let offleft = el.offsetleft, offtop = el.offsettop

// 在js層面進行計算

for(let i=0;i<10;i++)

// 一次性將計算結果應用到dom上

el.style.left = offleft + "px"

el.style.top = offtop + "px"

const container = document.getelementbyid('container')

container.style.width = '100px'

container.style.height = '200px'

container.style.border = '10px solid red'

container.style.color = 'red'

每次單獨操作,都去觸發一次渲染樹更改,從而導致相應的回流與重繪過程。

優化成乙個有 class 加持的樣子:

const container = document.getelementbyid('container')

container.style.csstext += 'width: 100px; height: 200px; border: 10px solid red; color: red;';

合併之後,等於我們將所有的更改一次性發出,用乙個 style 請求解決掉了。

我們給元素設定 display: none,將其從頁面上「拿掉」,將無法觸發回流與重繪——這個將元素「拿掉」的操作,就叫做 dom 離線。

let li;

for (let i = 0; i < data.length; i++)

}const ul = document.getelementbyid('list');

如果我們直接這樣執行的話,由於每次迴圈都會插入乙個新的節點,會導致瀏覽器回流一次。

優化操作:隱藏元素,應用修改,重新顯示

let li;

for (let i = 0; i < data.length; i++)

}const ul = document.getelementbyid('list');

ul.style.display = 'none';

ul.style.display = 'block';

當我們進行少量 dom 操作時,dom 離線化的優越性確實不太明顯。一旦操作頻繁起來,這「拿掉」和「放回」的開銷都將會是非常值得的。

參考:

回流與重繪

首先是html渲染過程 解析html並構建dom樹和cssom樹,瀏覽器對html標記轉換成文件物件模型,css標記則轉換成css物件模型 cssom dom 樹包含了所有的 html 標籤,包括不展示的 head 節點和 display none 的節點,而 cssom 樹則會去掉瀏覽器不能識別的...

重繪與回流

很多面試都會問到的問題,那麼說起這兩個概念,首先先了解一下,瀏覽器對乙個頁面對渲染過程。1.使用者輸入url位址,瀏覽器根據網域名稱查詢ip位址 2.瀏覽器向伺服器傳送http請求 3.伺服器接受請求,根據請求返回相應的html 返回給瀏覽器 4.瀏覽器接受到伺服器的相應結果,對頁面做解析渲染 1 ...

重繪與回流

dom樹結構變化 新增或者刪除可見的dom元素 元素幾何屬性發生變化 頁面渲染初始化 獲取某些屬性 瀏覽器視窗發生變化,即 resize事件發生 啟用css偽類 hover 改變元素顏色 改變元素背景色 將改變樣式的操作集合在一次完成,直接改變classname或csstext 讓要操作的元素進行離...