3分鐘 2023-01-31
初步認識 Reflow 回流和 Repaint 重繪
簡介
現今比較容易影響前端效能大多是 JavaScript ,操作大量 DOM 確實會給瀏覽器較大的負擔。而變更 CSS 也有造成效能的兩大元凶:重排(回流)(Reflow)和 重繪(Repaint),今天就來介紹一下這兩個名詞吧。
瀏覽器如何渲染畫面?
在開始介紹兩個名詞之前,要先了解瀏覽器如何渲染畫面的,才能知道這兩個名詞分別在渲染的哪個步驟以及他們的工作。
- 從 HTML 解析出 DOM 樹
- 從 CSS 解析出 CSSOM 樹
- 兩者組合出 Render TREE
- 計算出 Render 樹每個元素的位置、大小,以及每個節點畫面上的座標
- 實際將結果繪製到畫面上
DOM 樹雖然和 Render 樹很相似,但 Render 知道樣式的設定,例如把一個 div 的 display 屬性設定為 none,這個 div 在 Render 樹就不會出現。
重排(回流)(Reflow)
Reflow 會根據 Render 樹逐步計算每個元素的位置座標、大小,以及其是否顯示的屬性等,與這類屬性有關的物件操作都會觸發 Reflow,以下有一些簡單的舉例:
- 頁面首次被載入的時候
- 進行 CSS 屬性設定,如:大小(height、width)、定位與浮動(position、float),或是設定偽類別(:hover)等
- 使用者互動,如:調整視窗大小、按鈕的狀態變動等
- JavaScript 進行 DOM 操作、取得元素大小或是動態載入CSS等。
由於 Reflow 相當耗費運算資源,所以瀏覽器會採用批次處理,不會馬上就處理 Reflow 需求,而是放到列隊中,需要時(每一個 frame)才會批次執行並清空列隊。
重繪(Repaint)
Repaint 就是將經過 Reflow 計算後的結果轉換成螢幕上的實際像素,Repaint 會將可見元素的樣式變更(例如:元素的可見性、背景)重新繪製到畫面上,由於最後可見元素的變更都必須重新繪製到畫面上,Repaint 也就難以避免。
不要讓 Reflow 成為效能瓶頸
雖然 Reflow 在瀏覽器會被批次執行,但還是可以用一些方法來避免 Reflow,例如:
- 少變更或使用定位屬性,如不用 top 而改用 translate,top 之類的定位屬性是真實改變元素位置,而 translate 只是相較於原位置產生偏移
- 以 visibility: hidden 替換 display:none,由於 visibility 佔用位置,隱藏並不會產生 Reflow,而 display 不會佔用位置,隱藏則會產生 Reflow。
- 不要使用表格 table 排版,由於 Reflow 時有可能會連同子元素一起而導致整張表 Reflow。
- 避免過深的 DOM 樹、CSSOM 樹
- 避免過度頻繁更新樣式,如果要變更建議寫成 CSS 當中的 Class 一次完成變更。
如果上網路找文章,還能發現其他更多的方式,這裡就只列出我比較能理解的方式。
挑戰跨足工程師與設計師的反骨少年:D