【前端工程師手冊】學習迴流和重繪(reflow和repaint)

亞古發表於2018-08-01

瀏覽器的大概工作流程

以普通的HTML頁面為例:

  1. 解析HTML文件,生成dom樹
  2. 解析css產生css規則樹
  3. 解析JavaScript,通過DOM-API來操作dom樹和css規則樹
  4. 通過dom樹和css規則樹來構造渲染樹(rendering tree)
  5. 呼叫作業系統的GUI介面畫頁面

迴流(reflow)和重繪(repaint)

迴流:

元素的大小尺寸、位置發生變化時,會重新計算渲染樹,頁面要進行重新排版工作,這個過程即是迴流。<br>

重繪:

元素做了一些不影響排版的改變,比如背景色、下劃線等等,只需要重新繪製的過程,叫做重繪。

顯然迴流帶來的代價大於重繪,因為重繪僅僅是重新畫一遍元素而已,但是重繪是重新計算+重新畫

迴流的原因:

  • Initial。網頁初始化的時候。
  • Incremental。一些Javascript在操作DOM Tree時。
  • Resize。其些元件的尺寸變了
  • StyleChange。如果CSS的屬性發生變化了。
  • Dirty。幾個Incremental的reflow發生在同一個元素的子樹上。

更具體的說,就是這些常見的操作會引起迴流:

  1. 調整視窗大小
  2. 字型大小
  3. 樣式表變動
  4. 元素內容變化,尤其是輸入控制元件
  5. CSS偽類啟用,在使用者互動過程中發生
  6. DOM操作,DOM元素增刪、修改
  7. width, clientWidth, scrollTop等佈局寬高的計算

ps:但是瀏覽器並不會在我們一進行上面的操作就進行迴流,瀏覽器會積攢一批reflow然後一起進行迴流,不過有的操作會讓瀏覽器立馬進行迴流,比如resize視窗,改變了頁面預設的字型,或者說獲取以下這些值:

  • offsetTop, offsetLeft, offsetWidth, offsetHeight
  • scrollTop/Left/Width/Height
  • clientTop/Left/Width/Height
  • IE中的 getComputedStyle(), 或 currentStyle

如何減少reflow和repaint

  1. 避免頻繁的修改樣式,可以將要修改的多個樣式定義為一個class類,然後將類名一次賦值即可
  2. 把dom離線操作:

    • 使用documentFragment 物件在記憶體裡操作DOM
    • 先把DOM給display:none(有一次reflow),然後你想怎麼改就怎麼改。比如修改100次,然後再把他顯示出來。
    • clone一個DOM結點到記憶體裡,然後想怎麼改就怎麼改,改完後,和線上的那個的交換一下
  3. 不要把DOM結點的屬性值放在一個迴圈裡當成迴圈裡的變數。不然這會導致大量地讀寫這個結點的屬性。
  4. 為動畫的HTML元件使用fixed或absoult的position,那麼修改他們的CSS是不會reflow的,因為脫離了文件流

參考

減少重排與重繪

瀏覽器的渲染原理簡介

相關文章