瀏覽器的迴流與重繪 (Reflow & Repaint)

寫在前面

在討論迴流與重繪以前,咱們要知道:瀏覽器

  1. 瀏覽器使用流式佈局模型 (Flow Based Layout)。
  2. 瀏覽器會把HTML解析成DOM,把CSS解析成CSSOMDOMCSSOM合併就產生了Render Tree
  3. 有了RenderTree,咱們就知道了全部節點的樣式,而後計算他們在頁面上的大小和位置,最後把節點繪製到頁面上。
  4. 因爲瀏覽器使用流式佈局,對Render Tree的計算一般只須要遍歷一次就能夠完成,但table及其內部元素除外,他們可能須要屢次計算,一般要花3倍於同等元素的時間,這也是爲何要避免使用table佈局的緣由之一。

一句話:迴流必將引發重繪,重繪不必定會引發迴流。緩存

迴流 (Reflow)

Render Tree中部分或所有元素的尺寸、結構、或某些屬性發生改變時,瀏覽器從新渲染部分或所有文檔的過程稱爲迴流。佈局

會致使迴流的操做:性能

  • 頁面首次渲染
  • 瀏覽器窗口大小發生改變
  • 元素尺寸或位置發生改變
  • 元素內容變化(文字數量或圖片大小等等)
  • 元素字體大小變化
  • 添加或者刪除可見DOM元素
  • 激活CSS僞類(例如::hover
  • 查詢某些屬性或調用某些方法

一些經常使用且會致使迴流的屬性和方法:字體

  • clientWidthclientHeightclientTopclientLeft
  • offsetWidthoffsetHeightoffsetTopoffsetLeft
  • scrollWidthscrollHeightscrollTopscrollLeft
  • scrollIntoView()scrollIntoViewIfNeeded()
  • getComputedStyle()
  • getBoundingClientRect()
  • scrollTo()

重繪 (Repaint)

當頁面中元素樣式的改變並不影響它在文檔流中的位置時(例如:colorbackground-colorvisibility等),瀏覽器會將新樣式賦予給元素並從新繪製它,這個過程稱爲重繪。優化

性能影響

迴流比重繪的代價要更高。動畫

有時即便僅僅迴流一個單一的元素,它的父元素以及任何跟隨它的元素也會產生迴流。code

現代瀏覽器會對頻繁的迴流或重繪操做進行優化:隊列

瀏覽器會維護一個隊列,把全部引發迴流和重繪的操做放入隊列中,若是隊列中的任務數量或者時間間隔達到一個閾值的,瀏覽器就會將隊列清空,進行一次批處理,這樣能夠把屢次迴流和重繪變成一次。圖片

當你訪問如下屬性或方法時,瀏覽器會馬上清空隊列:

  • clientWidthclientHeightclientTopclientLeft

  • offsetWidthoffsetHeightoffsetTopoffsetLeft

  • scrollWidthscrollHeightscrollTopscrollLeft

  • widthheight

  • getComputedStyle()

  • getBoundingClientRect()

由於隊列中可能會有影響到這些屬性或方法返回值的操做,即便你但願獲取的信息與隊列中操做引起的改變無關,瀏覽器也會強行清空隊列,確保你拿到的值是最精確的。

如何避免

CSS

  • 避免使用table佈局。
  • 儘量在DOM樹的最末端改變class
  • 避免設置多層內聯樣式。
  • 將動畫效果應用到position屬性爲absolutefixed的元素上。
  • 避免使用CSS表達式(例如:calc())。

JavaScript

  • 避免頻繁操做樣式,最好一次性重寫style屬性,或者將樣式列表定義爲class並一次性更改class屬性。
  • 避免頻繁操做DOM,建立一個documentFragment,在它上面應用全部DOM操做,最後再把它添加到文檔中。
  • 也能夠先爲元素設置display: none,操做結束後再把它顯示出來。由於在display屬性爲none的元素上進行的DOM操做不會引起迴流和重繪。
  • 避免頻繁讀取會引起迴流/重繪的屬性,若是確實須要屢次使用,就用一個變量緩存起來。
  • 對具備複雜動畫的元素使用絕對定位,使它脫離文檔流,不然會引發父元素及後續元素頻繁迴流。
相關文章
相關標籤/搜索