一、前言
偶爾在面試過程中遇到過重匯與回流reflow的問題,畢竟頁面優化也是考核一個開發者能力的關鍵之一,上篇文章聊了下documentfragment也是為了減輕回流問題,那么本篇文章好好介紹下重繪和回流。
二、重繪和回流是什么
怎么去理解這兩個概念呢?從字面上理解,重繪,重新繪畫,重新上色,較難產生聯想的是回流。
我們都知道,一個頁面從加載到完成,首先是構建DOM樹,然后根據DOM節點的幾何屬性形成render樹(渲染樹),當渲染樹構建完成,頁面就根據DOM樹開始布局了,渲染樹也根據設置的樣式對應的渲染這些節點。
在這個過程中,回流與DOM樹,渲染樹有關,重繪與渲染樹有關,怎么去理解呢?
比如我們增刪DOM節點,修改一個元素的寬高,頁面布局發生變化,DOM樹結構發生變化,那么肯定要重新構建DOM樹,而DOM樹與渲染樹是緊密相連的,DOM樹構建完,渲染樹也會隨之對頁面進行再次渲染,這個過程就叫回流。
當你給一個元素更換顏色,這樣的行為是不會影響頁面布局的,DOM樹不會變化,但顏色變了,渲染樹得重新渲染頁面,這就是重匯。
你應該能感覺到,回流的代價要遠大於重繪。且回流必然會造成重繪,但重繪不一定會造成回流。
題外話
1.由於display為none的元素在頁面不需要渲染,渲染樹構建不會包括這些節點;但visibility為hidden的元素會在渲染樹中。因為display為none會脫離文檔流,visibility為hidden雖然看不到,但類似與透明度為0,其實還在文檔流中,還是有渲染的過程。
2.盡量避免使用表格布局,當我們不為表格td添加固定寬度時,一列的td的寬度會以最寬td的寬作為渲染標准,假設前幾行td在渲染時都渲染好了,結果下面某行的一個td特別寬,table為了統一寬,前幾行的td會回流重新計算寬度,這是個很耗時的事情。
三、重繪和回流有什么區別
結合上面的解釋,引起DOM樹結構變化,頁面布局變化的行為叫回流,且回流一定伴隨重繪。
只是樣式的變化,不會引起DOM樹變化,頁面布局變化的行為叫重繪,且重繪不一定會便隨回流。
它們的區別就像這樣:
回流往往伴隨着布局的變化,代價較大
重繪只是樣式的變化,結構不會變化
四、怎么減少回流
說了這么多,我們也知道了,回流要重新構建DOM樹,渲染樹也得重新渲染,很麻煩,哪么哪些行為會引起回流,怎么去避免呢?
1.DOM的增刪行為
比如你要刪除某個節點,給某個父元素增加子元素,這類操作都會引起回流。如果要加多個子元素,最好使用documentfragment。
2.幾何屬性的變化
比如元素寬高變了,border變了,字體大小變了,這種直接會引起頁面布局變化的操作也會引起回流。如果你要改變多個屬性,最好將這些屬性定義在一個class中,直接修改class名,這樣只用引起一次回流。
3.元素位置的變化
修改一個元素的左右margin,padding之類的操作,所以在做元素位移的動畫,不要更改margin之類的屬性,使用定位脫離文檔流后改變位置會更好。
4.獲取元素的偏移量屬性
例如獲取一個元素的scrollTop、scrollLeft、scrollWidth、offsetTop、offsetLeft、offsetWidth、offsetHeight之類的屬性,瀏覽器為了保證值的正確也會回流取得最新的值,所以如果你要多次操作,最取完做個緩存。
5.頁面初次渲染
這樣的回流無法避免
6.瀏覽器窗口尺寸改變
resize事件發生也會引起回流。
這里就不列舉引起重繪的行為了,記住,回流一定伴隨着重繪,所以上面的行為都會重繪,除此之外,例如修改背景顏色,字體顏色之類不影響布局的行為都只引發重繪。
如果對於documentfragment文檔片段感興趣,可以閱讀博主這篇文章