應該知道的前端效能二三事 —— Reflow 和 Repaint

weixin_34208283發表於2017-07-24

移動 Web 前端開發,目前是火的不能再火了。到處都在招什麼 H5 工程師、Hybrid App 開發工程師,主要負責的其實就是一些移動 Web 前端開發的工作。稍微有過一些前端經驗的人都知道,手機上的開銷比 PC 上要大的多,你在 PC 的模擬器上除錯的很順暢,等到手機上時,就會卡,這是為什麼呢?其實這就是效能問題,有其他的開銷佔用了你的計算資源啦,那麼是哪些開銷佔用了呢?拋開後端介面慢啊、網路狀態差啊什麼的不說,我們們今天聊聊瀏覽器本身的細節,Reflow 和 Repaint。尤其是在新增一些 CSS3 動畫或者批量操作多個 DOM 元素的時候,Reflow 和 Repaint 的影響就會更加大。

啥是 Reflow 和 Repaint

Repaint
Repaint 就是「重繪」,它會在你改變 DOM 元素的視覺效果時進行,改變佈局時不會觸發。比如,opacity,background-color,visibility和outline等都會觸發,「重繪」的開銷還是比較昂貴的,因為瀏覽器會在某一個 DOM 元素的視覺效果改變後去 check 這個 DOM 元素內的所有節點。

Reflow
Reflow 就是「迴流」,它的影響更大。它會在某一個 DOM 元素的位置發生改變後觸發,而且它會重新計算所有元素的位置和在頁面中的佔有的面積,這樣的話將會引起頁面某一個部分甚至整個頁面的重新渲染。改變某一個元素會影響它所有的子節點 (children)、祖先節點 (ancestors) 及兄弟節點(siblings)。

Reflow 和 Repaint 都是瀏覽器慢的元凶

Reflow 的開銷更加昂貴,那麼具體哪些時候會觸發 Reflow?

  • 新增、刪除或者改變 DOM 元素的可見性時:使用 JS 去改變 DOM 元素時會觸發 Reflow。

  • 新增、刪除或者改變 CSS 樣式:直接改變 CSS Style 或者元素的 class 可能會影響佈局,還有改變一個元素的寬度能夠影響它所在的 DOM 節點中的所有元素,以及它周圍的那些元素。

  • CSS3 動畫(animation)和過渡(transition): 動畫的每一 frame 都會觸發 Reflow。

  • 使用 offsetWidth 和 offsetHeight:這一點很特別,你讀一個 DOM 的 offsetWidth 和 offsetHeight 屬性同樣會觸發一下 Reflow,因為這兩個屬性需要依賴一些元素去計算。

  • 使用者互動:使用者可以通過 hover 一下 a 連結,在 input 裡面輸入文字,拖動瀏覽器的大小,改變字型大小,更換樣式表或者字型等都會觸發 reflow。

一些常用的提高效能的原則

佈局
不要用inline style 或 table 佈局,flexbox 佈局也會給效能帶來一些小困擾。inline style會在 html 下載完後進行一次額外的 Reflow,table佈局的開銷遠比其他 DOM 元素的佈局開銷要大。flexboxitem 會在 HTML 下載完成後改變尺寸。

簡寫 CSS

儘量簡寫 CSS,避免使用複雜的 CSS 選擇器,使用 UnusedCSS, uCSS, gulp-uncss可以有效的減少樣式的定義和檔案的大小。

優化 DOM

減少 DOM 的層級,減少 DOM 的數量,如果不需適配老瀏覽器,刪掉一些無用的 wrapper 性質的 DOM 元素,總之越少越好。

慎改 class

在一個 DOM 樹中,儘可能改那些沒有特別多子元素 DOM 的 class,子元素少的可以改,多的不推薦。

避免複雜動畫

刪掉複雜的動畫,運用動畫的元素儘量是 position:absolute 或 position:fixed 的,這樣會讓他們脫離文件流,不去影響其他的元素。

善用 display:none

display:none 的元素不會引發 Reflow 和 Repaint,可以在讓這些元素在 display 之前進行一些諸如顏色、尺寸什麼的改變。

避免大量 DOM 互相影響

比如 Tabs 這種場景,如果你點選一個 Tab 會顯示它控制的區塊,顯示的那個區塊會影響其他的區塊,這樣可能會引起 Reflow,因為它們的高度不一樣,可以通過定個高度來優化這種場景。

效能永遠比酷炫重要

記住一個原則,你網頁的動畫再牛逼,效能還是第一位的,如果每一幀移動1個畫素會造成你的頁面卡頓,那寧願每一幀移動10畫素讓動畫的幀變得遲鈍一些,也不要讓頁面的效能降下來。

相關文章