淺談瀏覽器渲染、迴流和重繪

概要

  1. 瀏覽器渲染的本質;
  2. 介紹迴流 reflow 和重繪 repaint
  3. 如何優化性能;

瀏覽器渲染

一個普通的網頁,瀏覽器在渲染前須要先構建 DOM(document object model) 和 CSSOM (css object model) 樹。css

DOM

DOM 樹是怎麼來的呢?咱們先假設有一個網頁由一些文本,一幅圖片組成:前端

瀏覽器會通過:瀏覽器

  • 轉換:瀏覽器從磁盤或網絡讀取 HTML 的原始字節,並根據文件的指定編碼將它們轉換成各個字符。
  • 令牌化: 瀏覽器將字符串轉換成 W3C 標準規定的各類令牌,例如,「」、「」,以及其餘尖括號內的字符串。每一個令牌都具備特殊含義和一組規則。
  • 詞法分析:令牌轉換成定義其屬性和規則的「對象」。
  • DOM 構建:因爲 HTML 標記定義不一樣標記之間的關係(一些標記包含在其餘標記內),建立的對象連接在一個樹數據結構內,此結構也會捕獲標記中定義的父子關係:HTML 對象是 body 對象的父項,body 是 paragraph 對象的父項,依此類推。

整個過程的最終輸出是咱們這個普通頁面的文檔對象模型 (DOM),瀏覽器對頁面的後續處理都會用到它。緩存

瀏覽器每次處理 HTML 標籤時,都須要花費時間來完成上面的每一個步驟,一個頁面有大量 HTML 處理時須要花費更多時間。網絡

CSSOM

與處理 HTML 時同樣,瀏覽器引擎須要將收到的 CSS 規則轉化成瀏覽器能理解和處理的東西。數據結構

CSS 字節轉換成字符,接着轉換成令牌和節點,最後連接到一個稱爲「CSS 對象模型」(CSSOM) 的樹結構內。構建 CSSOM 樹是一個十分消耗性能的過程。佈局

最後 CSSOM 樹和 DOM 樹合併成渲染樹,並用它計算每一個可見元素的佈局,而後輸出給繪製流程,最終將像素渲染到屏幕上。性能

迴流 reflow 和重繪 repaint

reflow 有些地方譯成重排。字體

字面意思上理解重繪:從新描繪某個區域。優化

理解迴流要複雜一些,咱們增刪 DOM 節點,修改一個元素尺寸,頁面佈局和 DOM 樹結構發生變化,確定須要從新構建 DOM 樹,而 DOM 樹與渲染樹是緊密相連的,DOM 樹構建完,渲染樹也會隨之對頁面進行再次渲染。

重繪:對 DOM 操做簡單修改樣式(好比修改元素的 visibilitycolorbackground-color 等)、卻並未影響頁面佈局時,瀏覽器不需從新計算元素的位置尺寸等,直接爲該元素繪製新的樣式。這個過程叫作重繪。

迴流:對 DOM 操做致使 DOM 尺寸等屬性的變化(好比修改元素的 widthheighttop)時,瀏覽器須要從新計算元素的屬性,而後再將計算的結果繪製出來,這個過程叫作迴流。

常見的會致使迴流的操做:

  • 頁面首次加載
  • 瀏覽器窗口尺寸改變
  • 元素尺寸或位置改變
  • 元素內容變化
  • 元素字體大小變化
  • 增刪 DOM 元素
  • 查詢或調用某些特定屬性方法

總結:

  1. 迴流每每代價比重繪大;
  2. 迴流必定重繪,重繪未必迴流。

現代瀏覽器優化

由於頻繁修改 DOMCSSOM 自己是件特別耗費性能的事情,現代瀏覽器大多對於都作了必定的優化。好比會把一系列的操做放進隊列機制來批量更新佈局,至少一個瀏覽器刷新幀 16ms(即大多數顯示屏幕的刷新率爲 60Hz,一個刷新間隔爲 1000ms/60)纔會清空隊列(節流優化~)。

但在獲取佈局尺寸等信息的時候,爲了保證數據的準確性,隊列中不管有沒有會影響這些屬性或方法返回值的操做,瀏覽器也會強制清空隊列,觸發迴流與重繪。( IE 不保證有這些優化)

  • offsetTopoffsetLeftoffsetWidthoffsetHeight
  • scrollTopscrollLeftscrollWidthscrollHeight
  • clientTopclientLeftclientWidthclientHeight
  • widthheight
  • getComputedStyle()
  • getBoundingClientRect()

優化迴流和重繪

  • 避免使用 CSS 表達式;
  • 使用 transform 替代 top
  • CSS3 硬件加速(GPU 加速);
  • 離線操做 DOM:把元素脫離文檔流,而後對元素進行修改,這樣只會致使重繪,而不會形成迴流。
    • display:none:臨時把元素 脫離文檔流,進行批量操做後再放回。這樣只會有一次迴流;
    • createDocumentFragment:建立文檔片斷,一次性把內容放進文檔;
  • 儘量在 DOM 樹的最末端改變 class:減少迴流的範圍;
  • 將動畫效果應用到 position 屬性爲 absolutefixed 的元素上,避免影響其餘元素的佈局,這樣只是一個重繪,而不是迴流;
  • JS 避免頻繁讀取會引起迴流/重繪的屬性:若是須要頻繁使用,能夠用變量把它緩存下來。

關注咱們

公衆號@前端論道