瀏覽器的回流與重繪 (Reflow & Repaint)

瀏覽器的回流與重繪 (Reflow & Repaint)

寫(xiě)在前面

在討論回流與重繪之前,我們要知道:

瀏覽器使用流式布局模型 (Flow Based Layout)。

瀏覽器會(huì)把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就產(chǎn)生了Render Tree。

有了RenderTree,我們就知道了所有節(jié)點(diǎn)的樣式,然后計(jì)算他們?cè)陧?yè)面上的大小和位置,最后把節(jié)點(diǎn)繪制到頁(yè)面上。

由于瀏覽器使用流式布局,對(duì)Render Tree的計(jì)算通常只需要遍歷一次就可以完成,但table及其內(nèi)部元素除外,他們可能需要多次計(jì)算,通常要花3倍于同等元素的時(shí)間,這也是為什么要避免使用table布局的原因之一。

一句話(huà):回流必將引起重繪,重繪不一定會(huì)引起回流。

回流 (Reflow)

當(dāng)Render Tree中部分或全部元素的尺寸、結(jié)構(gòu)、或某些屬性發(fā)生改變時(shí),瀏覽器重新渲染部分或全部文檔的過(guò)程稱(chēng)為回流。

會(huì)導(dǎo)致回流的操作:

頁(yè)面首次渲染

瀏覽器窗口大小發(fā)生改變

元素尺寸或位置發(fā)生改變

元素內(nèi)容變化(文字?jǐn)?shù)量或圖片大小等等)

元素字體大小變化

添加或者刪除可見(jiàn)的DOM元素

激活CSS偽類(lèi)(例如::hover)

查詢(xún)某些屬性或調(diào)用某些方法

一些常用且會(huì)導(dǎo)致回流的屬性和方法:

clientWidth、clientHeight、clientTop、clientLeft

offsetWidth、offsetHeight、offsetTop、offsetLeft

scrollWidth、scrollHeight、scrollTop、scrollLeft

scrollIntoView()、scrollIntoViewIfNeeded()

getComputedStyle()

getBoundingClientRect()

scrollTo()

重繪 (Repaint)

當(dāng)頁(yè)面中元素樣式的改變并不影響它在文檔流中的位置時(shí)(例如:color、background-color、visibility等),瀏覽器會(huì)將新樣式賦予給元素并重新繪制它,這個(gè)過(guò)程稱(chēng)為重繪。

性能影響

回流比重繪的代價(jià)要更高。

有時(shí)即使僅僅回流一個(gè)單一的元素,它的父元素以及任何跟隨它的元素也會(huì)產(chǎn)生回流。

現(xiàn)代瀏覽器會(huì)對(duì)頻繁的回流或重繪操作進(jìn)行優(yōu)化:

瀏覽器會(huì)維護(hù)一個(gè)隊(duì)列,把所有引起回流和重繪的操作放入隊(duì)列中,如果隊(duì)列中的任務(wù)數(shù)量或者時(shí)間間隔達(dá)到一個(gè)閾值的,瀏覽器就會(huì)將隊(duì)列清空,進(jìn)行一次批處理,這樣可以把多次回流和重繪變成一次。

當(dāng)你訪(fǎng)問(wèn)以下屬性或方法時(shí),瀏覽器會(huì)立刻清空隊(duì)列:

clientWidth、clientHeight、clientTop、clientLeft

offsetWidth、offsetHeight、offsetTop、offsetLeft

scrollWidth、scrollHeight、scrollTop、scrollLeft

width、height

getComputedStyle()

getBoundingClientRect()

因?yàn)殛?duì)列中可能會(huì)有影響到這些屬性或方法返回值的操作,即使你希望獲取的信息與隊(duì)列中操作引發(fā)的改變無(wú)關(guān),瀏覽器也會(huì)強(qiáng)行清空隊(duì)列,確保你拿到的值是最精確的。

如何避免

CSS

避免使用table布局。

盡可能在DOM樹(shù)的最末端改變class。

避免設(shè)置多層內(nèi)聯(lián)樣式。

將動(dòng)畫(huà)效果應(yīng)用到position屬性為absolute或fixed的元素上。

避免使用CSS表達(dá)式(例如:calc())。

JavaScript

避免頻繁操作樣式,最好一次性重寫(xiě)style屬性,或者將樣式列表定義為class并一次性更改class屬性。

避免頻繁操作DOM,創(chuàng)建一個(gè)documentFragment,在它上面應(yīng)用所有DOM操作,最后再把它添加到文檔中。

也可以先為元素設(shè)置display: none,操作結(jié)束后再把它顯示出來(lái)。因?yàn)樵赿isplay屬性為none的元素上進(jìn)行的DOM操作不會(huì)引發(fā)回流和重繪。

避免頻繁讀取會(huì)引發(fā)回流/重繪的屬性,如果確實(shí)需要多次使用,就用一個(gè)變量緩存起來(lái)。

對(duì)具有復(fù)雜動(dòng)畫(huà)的元素使用絕對(duì)定位,使它脫離文檔流,否則會(huì)引起父元素及后續(xù)元素頻繁回流。




作者:腰花

鏈接:https://juejin.im/post/5a9923e9518825558251c96a

來(lái)源:掘金

著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容