reflow 與 repant

1.瀏覽器渲染機(jī)制
瀏覽器采用流式布局模型(Flow Based Layout)
瀏覽器會(huì)把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就產(chǎn)生了渲染樹(shù)(Render Tree)。
有了渲染樹(shù),瀏覽器就知道了所有節(jié)點(diǎn)的樣式,然后計(jì)算它們?cè)陧?yè)面上的大小和位置,最后把節(jié)點(diǎn)繪制到頁(yè)面上。過(guò)程如圖(來(lái)源MDN

image

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

2. reflow(回流):布局或者幾何屬性改變,瀏覽器為了重新渲染部分或整個(gè)頁(yè)面,重新計(jì)算頁(yè)面元素位置和幾何結(jié)構(gòu)的操作。
由于 reflow 是一種瀏覽器中的用戶(hù)攔截(user-blocking)操作,所以了解不同的文檔屬性(DOM 層級(jí)(DOM depth),CSS 效率,不用類(lèi)型的 style 變化)對(duì) reflow 次數(shù)的影響,以及如何減少 reflow 次數(shù),非常必要。(一個(gè)元素的回流可能會(huì)導(dǎo)致了其所有子元素以及DOM中緊隨其后的節(jié)點(diǎn)、祖先節(jié)點(diǎn)元素的隨后的回流。)

3. repaint(重繪):是在一個(gè)元素的外觀被改變,但沒(méi)有改變布局的情況下發(fā)生,如改變visibility、outline、前景色、背景色、color等。
"According to Opera, repaint is expensive because the browser must verify the visibility of all other nodes in the DOM tree."
當(dāng)repaint發(fā)生時(shí),瀏覽器會(huì)驗(yàn)證DOM樹(shù)上的所有其它結(jié)點(diǎn)的visibility屬性,所以代價(jià)高昂。

reflow(回流)是導(dǎo)致DOM腳本執(zhí)行低效的關(guān)鍵因素之一。頁(yè)面上任何一個(gè)結(jié)點(diǎn)觸發(fā)reflow,都會(huì)導(dǎo)致它的子結(jié)點(diǎn)及祖先結(jié)點(diǎn)重新渲染。回流必定會(huì)發(fā)生重繪,重繪不一定會(huì)引發(fā)回流。

在下列情況下會(huì)導(dǎo)致reflow發(fā)生:

  • 改變窗囗大小
  • 改變文字大小
  • 添加/刪除樣式表
  • 內(nèi)容的改變,如用戶(hù)在輸入框中敲字(這樣也會(huì)-_-||)
  • 激活偽類(lèi),如:hover (IE里是一個(gè)兄弟結(jié)點(diǎn)的偽類(lèi)被激活)
  • 操作class屬性
  • 腳本操作DOM
  • 計(jì)算offsetWidth和offsetHeight等
  • 設(shè)置style屬性

4. 瀏覽器優(yōu)化
現(xiàn)代瀏覽器大多都是通過(guò)隊(duì)列機(jī)制來(lái)批量更新布局,瀏覽器會(huì)把修改操作放在隊(duì)列中,至少一個(gè)瀏覽器刷新(即16.6ms)才會(huì)清空隊(duì)列,但當(dāng)你獲取布局信息的時(shí)候,隊(duì)列中可能有會(huì)影響這些屬性或方法返回值的操作,即使沒(méi)有,瀏覽器也會(huì)強(qiáng)制清空隊(duì)列,觸發(fā)回流與重繪來(lái)確保返回正確的值。
主要包括以下屬性或方法:
offsetTop、offsetLeft、offsetWidth、offsetHeight
scrollTop、scrollLeft、scrollWidth、scrollHeight
clientTop、clientLeft、clientWidth、clientHeight
width、height
getComputedStyle()
getBoundingClientRect()
所以,我們應(yīng)該避免頻繁的使用上述的屬性,他們都會(huì)強(qiáng)制渲染刷新隊(duì)列。

5. 減少重繪與回流

(一)CSS

1)使用 transform 替代 top;
2)使用 visibility 替換 display: none ,因?yàn)榍罢咧粫?huì)引起重繪,后者會(huì)引發(fā)回流
3)避免使用table布局,可能很小的一個(gè)小改動(dòng)會(huì)造成整個(gè) table 的重新布局。
4)盡可能在DOM樹(shù)的最末端改變class,回流是不可避免的,但可以減少其影響。盡可能在DOM樹(shù)的最末端改變class,可以限制了回流的范圍,使其影響盡可能少的節(jié)點(diǎn)。
5)避免設(shè)置多層內(nèi)聯(lián)樣式,CSS 選擇符從右往左匹配查找,避免節(jié)點(diǎn)層級(jí)過(guò)多。

     <div>
       <a> <span></span> </a>
     </div>
     <style>
       span {
         color: red;
       }
       div > a > span {
         color: red;
       }
     </style>

對(duì)于第一種設(shè)置樣式的方式來(lái)說(shuō),瀏覽器只需要找到頁(yè)面中所有的 span 標(biāo)簽然后設(shè)置顏色,但是對(duì)于第二種設(shè)置樣式的方式來(lái)說(shuō),瀏覽器首先需要找到所有的 span 標(biāo)簽,然后找到 span 標(biāo)簽上的 a 標(biāo)簽,最后再去找到 div 標(biāo)簽,然后給符合這種條件的 span 標(biāo)簽設(shè)置顏色,這樣的遞歸過(guò)程就很復(fù)雜。所以我們應(yīng)該盡可能的避免寫(xiě)過(guò)于具體的 CSS 選擇器,然后對(duì)于 HTML 來(lái)說(shuō)也盡量少的添加無(wú)意義標(biāo)簽,保證層級(jí)扁平。

6)將動(dòng)畫(huà)效果應(yīng)用到position屬性為absolute或fixed的元素上,使它脫離文檔流,避免影響其他元素的布局,這樣只是一個(gè)重繪,而不是回流,同時(shí),控制動(dòng)畫(huà)速度可以選擇 requestAnimationFrame,詳見(jiàn)探討 requestAnimationFrame。

7)避免使用CSS表達(dá)式,可能會(huì)引發(fā)回流。
8)將頻繁重繪或者回流的節(jié)點(diǎn)設(shè)置為圖層,圖層能夠阻止該節(jié)點(diǎn)的渲染行為影響別的節(jié)點(diǎn),例如will-change、video、iframe等標(biāo)簽,瀏覽器會(huì)自動(dòng)將該節(jié)點(diǎn)變?yōu)閳D層。
9)CSS3 硬件加速(GPU加速),使用css3硬件加速,可以讓transform、opacity、filters、Will-change這些動(dòng)畫(huà)不會(huì)引起回流重繪 。但是對(duì)于動(dòng)畫(huà)的其它屬性,比如background-color這些,還是會(huì)引起回流重繪的,不過(guò)它還是可以提升這些動(dòng)畫(huà)的性能。

(二)JS

1)避免頻繁操作樣式,最好一次性重寫(xiě)style屬性,或者將樣式列表定義為class并一次性更改class屬性。
2)避免頻繁操作DOM,創(chuàng)建一個(gè)documentFragment,在它上面應(yīng)用所有DOM操作,最后再把它添加到文檔中。
3)避免頻繁讀取會(huì)引發(fā)回流/重繪的屬性,如果確實(shí)需要多次使用,就用一個(gè)變量緩存起來(lái)。

總結(jié):

回流與重繪涉及瀏覽器的性能表現(xiàn),涉及的知識(shí)點(diǎn)眾多且零碎,記住主要的就行了。更細(xì)致的解釋見(jiàn)你真的了解回流和重繪嗎

?著作權(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ù)。

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