前端百題斬之從渲染流程認(rèn)識(shí)重繪和回流
在“瀏覽器的渲染流程”一節(jié)中已經(jīng)詳細(xì)闡述了渲染過程的幾個(gè)關(guān)鍵步驟,其簡(jiǎn)要流程圖如下所示:
今天的主角“重繪和回流”就會(huì)導(dǎo)致瀏覽器觸發(fā)更新,重新進(jìn)行渲染繪制,但是兩者稍有不同,重繪不會(huì)存在布局階段,而回流會(huì)進(jìn)行重新布局,所以回流代價(jià)更高、損耗更大。
31.1 重繪
重繪是指頁面中某些元素發(fā)生了不影響布局的變化時(shí)(如顏色改變),瀏覽器重新繪制的過程。此時(shí)由于只需要UI層面的重新像素繪制,因此損耗較少。僅僅引發(fā)重繪的操作如下所示(注意:回流必定觸發(fā)重繪,但是重繪不一定觸發(fā)回流):
- 改變背景色;
- 改變文字顏色;
- 改變邊框顏色;
- 通過visibility:hidden隱藏元素;
- ……
31.2 回流
回流是指頁面中某些元素發(fā)生變化而影響了布局時(shí)(如尺寸、位置改變),瀏覽器需要重新布局并繪制的過程。引發(fā)回流的操作如下所示:
- 頁面初次渲染;
- 瀏覽器窗口大小改變;
- 元素尺寸、位置、內(nèi)容發(fā)生改變;
- 元素字體大小變化;
- 添加或者刪除可見的 dom 元素;
- 激活 CSS 偽類(例如::hover);
- 查詢某些屬性或調(diào)用某些方法:
- clientWidth、clientHeight、clientTop、clientLeft
- offsetWidth、offsetHeight、offsetTop、offsetLeft
- scrollWidth、scrollHeight、scrollTop、scrollLeft
- getComputedStyle() :Window.getComputedStyle()方法返回一個(gè)對(duì)象,該對(duì)象在應(yīng)用活動(dòng)樣式表并解析這些值可能包含的任何基本計(jì)算后報(bào)告元素的所有CSS屬性的值。
- getBoundingClientRect()
- scrollTo():scrollTo() 方法可把內(nèi)容滾動(dòng)到指定的坐標(biāo)。
31.3 減少回流和重繪
31.3.1 瀏覽器自身優(yōu)化策略
由于每次重排都會(huì)造成額外的計(jì)算消耗,因此大多數(shù)瀏覽器都會(huì)通過隊(duì)列化修改并批量執(zhí)行來優(yōu)化重排過程。瀏覽器會(huì)將修改操作放入隊(duì)列里,直到過了一段時(shí)間或者操作達(dá)到了一個(gè)閾值,才清空隊(duì)列。當(dāng)你獲取布局信息的操作的時(shí)候,會(huì)強(qiáng)制隊(duì)列刷新,比如訪問以下屬性或者使用以下方法:
- offsetTop、offsetLeft、offsetWidth、offsetHeight
- scrollTop、scrollLeft、scrollWidth、scrollHeight
- clientTop、clientLeft、clientWidth、clientHeight
- getComputedStyle()
- getBoundingClientRect
以上屬性和方法都需要返回最新的布局信息,因此瀏覽器不得不清空隊(duì)列,觸發(fā)回流重繪來返回正確的值。因此,在修改樣式的時(shí)候,最好避免使用上面列出的屬性,它們都會(huì)刷新渲染隊(duì)列。如果要使用它們,最好將值緩存起來。
另一優(yōu)化就是瀏覽器認(rèn)為position為absolute或fixed的元素更改只會(huì)影響其本身和子元素,而static的元素變化則會(huì)影響之后的所有元素。原因在于absolute和fixed認(rèn)為元素從文檔流中清除了,怎么操作是內(nèi)部的事。例如:對(duì)于復(fù)雜動(dòng)畫效果,使用絕對(duì)定位讓其脫離文檔流
31.3.2 多次操作變?yōu)橐淮尾僮?/strong>
不要一條一條的修改DOM的樣式,盡量使用class進(jìn)行樣式修改。
把DOM離線修改(批量修改DOM)
(1)使用documentFragment對(duì)象在內(nèi)存里操作DOM
(2)先把DOM給display:none,修改完畢再顯示出來
(3)clone一個(gè)DOM節(jié)點(diǎn)到內(nèi)存里,然后想怎么改就怎么改,改完后,和在線的那個(gè)的交換一下。
31.3.3 其它
使用css3硬件加速,可以讓transform、opacity、filters(濾鏡)這些動(dòng)畫不會(huì)引起回流重繪(注意:對(duì)于動(dòng)畫的其它屬性,比如background-color這些,還是會(huì)引起回流重繪的,不過它還是可以提升這些動(dòng)畫的性能)
不要把DOM結(jié)點(diǎn)的屬性值放在一個(gè)循環(huán)里當(dāng)成循環(huán)里的變量。不然這會(huì)導(dǎo)致大量地讀寫這個(gè)結(jié)點(diǎn)的屬性。
千萬不要使用table布局。因?yàn)榭赡芎苄〉囊粋€(gè)小改動(dòng)會(huì)造成整個(gè)table的重新布局。
本文轉(zhuǎn)載自微信公眾號(hào)「執(zhí)鳶者」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系執(zhí)鳶者公眾號(hào)。