一、前情回顧 在討論迴流與重繪之前,我們要知道: 瀏覽器使用流式佈局模型 (Flow Based Layout)。 瀏覽器會把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合併就產生了Render Tree。 有了RenderTree,我們就知道了所有節點的樣式,然後計算他們在頁 ...
一、前情回顧
-
在討論迴流與重繪之前,我們要知道:
- 瀏覽器使用流式佈局模型 (Flow Based Layout)。
- 瀏覽器會把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合併就產生了Render Tree。
- 有了RenderTree,我們就知道了所有節點的樣式,然後計算他們在頁面上的大小和位置,最後把節點繪製到頁面上。
- 由於瀏覽器使用流式佈局,對Render Tree的計算通常只需要遍歷一次就可以完成,但table及其內部元素除外,他們可能需要多次計算,通常要花3倍於同等元素的時間,這也是為什麼要避免使用table佈局的原因之一。
二、迴流/重排
- 概念:當渲染樹中部分或者全部元素的尺寸、結構或者屬性發生變化時,瀏覽器會重新渲染部分或者全部文檔的過程就稱為迴流/重排。
- 觸發條件:
- 頁面的首次渲染
- 瀏覽器的視窗大小發生變化
- 元素的內容發生變化
- 元素的尺寸或者位置發生變化
- 元素的字體大小發生變化
- 激活CSS偽類
- 查詢某些屬性或者調用某些方法
- 添加或者刪除可見的DOM元素
三、重繪
- 概念:當頁面中某些元素的樣式發生變化,但是不會影響其在文檔流中的位置時,瀏覽器就會對元素進行重新繪製,這個過程就是重繪。
- 觸發條件:
- color、background 相關屬性:background-color、background-image 等
- outline 相關屬性:outline-color、outline-width 、text-decoration
- border-radius、visibility、box-shadow
四、如何避免迴流與重繪
- 瀏覽器針對頁面的迴流與重繪,進行了自身的優化——渲染隊列
- 瀏覽器會將所有的迴流、重繪的操作放在一個隊列中,當隊列中的操作到了一定的數量或者到了一定的時間間隔,瀏覽器就會對隊列進行批量處理。這樣就會讓多次的迴流、重繪變成一次迴流重繪。
- CSS
- 避免設置多層內聯樣式。
- 如果需要設置動畫效果,最好使用absolute或者fixed,使元素脫離文檔流,這樣他們發生變化就不會影響其他元素。
- 避免使用CSS表達式(例如:calc())。
- JS
- 避免頻繁操作樣式,最好將樣式列表定義為class並一次性更改class屬性。避免頻繁操作樣式,最好將樣式列表定義為class並一次性更改class屬性。
- 避免頻繁操作DOM,創建一個documentFragment,在它上面應用所有DOM操作,最後再把它添加到文檔中。
- 可以先為元素設置為不可見:display: none,操作結束後再把它顯示出來。因為在display屬性為none的元素上進行的DOM操作不會引發迴流和重繪。
五、解釋上述的documentFragment
- 概念:DocumentFragment,文檔片段介面,一個沒有父對象的最小文檔對象。它被作為一個輕量版的 Document使用,就像標準的document一樣,存儲由節點(nodes)組成的文檔結構。與document相比,最大的區別是DocumentFragment不是真實 DOM 樹的一部分,它的變化不會觸發 DOM 樹的重新渲染,且不會導致性能等問題。
- 與直接操作DOM的區別:由於DocumentFragment不會出現在文檔樹中,將DocumentFragment插入文檔樹中,相當於把把他的子孫節點插入到文檔樹中,在頻繁的DOM操作時,我們就可以將DOM元素插入DocumentFragment,之後一次性的將所有的子孫節點插入文檔中。和直接操作DOM相比,將DocumentFragment 節點插入DOM樹時,僅會觸發頁面的一次重繪,這樣就大大提高了頁面的性能。
六、總結
迴流一定重繪,重繪不一定迴流。