在前端開發中,有很多操作會引起 Reflow(迴流)和 Repaint(重繪)。理解這些操作有助於開發者最佳化頁面效能,減少卡頓,提升使用者體驗。
Reflow (迴流) 定義: 當瀏覽器需要重新計算元素的幾何尺寸和位置時,就會發生迴流。迴流的成本比重繪高得多,因為它會影響到整個文件的佈局,甚至觸發子元素甚至父元素以及後續元素的迴流。
Repaint (重繪) 定義: 當元素的外觀發生改變,但沒有改變佈局(例如,改變顏色、背景色、字型樣式等)時,就會發生重繪。
引起 Reflow 和 Repaint 的操作:
以下操作通常會引起迴流和重繪,其中一些操作的影響更大:
- 改變 DOM 元素的幾何屬性: 例如寬度、高度、padding、margin、border、display、position 等。
- 新增或刪除 DOM 元素: 對 DOM 樹的修改會影響佈局,從而導致迴流。
- 移動 DOM 元素: 使用
offsetLeft
、offsetTop
、offsetWidth
、offsetHeight
等屬性獲取元素的位置和尺寸資訊,這些操作會強制瀏覽器進行迴流以獲取最新的值。 儘量避免在迴圈中讀取這些屬性。 - 改變 CSS 樣式: 很多樣式的改變都會導致迴流,例如字型大小、字型樣式、文字內容等。
- 改變瀏覽器視窗大小 (resize): 視窗大小的改變會強制所有元素重新計算佈局。
- 滾動頁面 (scroll): 滾動頁面會觸發部分元素的重新佈局和繪製。
- :hover 偽類樣式: :hover 樣式的應用可能會導致迴流和重繪,尤其是在 hover 樣式影響佈局的情況下。
- 計算
offsetWidth
和offsetHeight
: 訪問這些屬性會強制瀏覽器進行迴流以返回正確的值。 - 設定
style
屬性: 直接操作元素的 style 屬性會觸發迴流和重繪。
減少 Reflow 和 Repaint 的方法:
- 批次修改 DOM: 使用 DocumentFragment 建立一個文件片段,在片段中進行 DOM 操作,最後一次性新增到文件中,減少迴流次數。
- 使用 CSS3 屬性: 例如 transform 和 opacity,這些屬性的改變不會觸發迴流,只會觸發重繪,效能更好。
- 避免頻繁讀取會觸發迴流的屬性: 例如
offsetLeft
、offsetTop
、offsetWidth
、offsetHeight
等。快取這些值,避免重複讀取。 - 使用
class
操作樣式: 避免直接操作style
屬性,使用 class 來修改樣式,瀏覽器可以批次處理樣式更改。 - 離線渲染: 使用 Canvas 或 SVG 進行繪製,可以避免瀏覽器迴流和重繪。
- 使用
will-change
屬性:will-change
屬性可以告知瀏覽器哪些元素可能會發生變化,瀏覽器可以提前進行最佳化。 但是要謹慎使用,過度使用反而會降低效能。 - Debounce 和 Throttle: 對於 resize 和 scroll 等頻繁觸發的事件,可以使用 Debounce 和 Throttle 技術來減少事件處理的頻率,從而減少迴流和重繪。
透過理解 Reflow 和 Repaint 的原理,並採取相應的最佳化措施,可以顯著提升網頁的效能和使用者體驗。