Web Vitals中階
回流 (reflow) 和重繪 (repaint) 是什麼?以及如何優化?
什麼是 Reflow(回流)與 Repaint(重繪)?
瀏覽器渲染流程大致為:
JS → Style → Layout(Reflow)→ Paint(Repaint)→ Composite
- Reflow(回流/重排):元素的幾何屬性(尺寸、位置、結構)改變,瀏覽器必須重新計算 Layout,再重新繪製。
- Repaint(重繪):元素的外觀屬性(如顏色、背景、visibility)改變,但不影響版面,瀏覽器只需重新 Paint,不需要 Layout。
Reflow 一定伴隨 Repaint;Repaint 不一定會觸發 Reflow。Reflow 的成本遠高於 Repaint。
哪些操作會觸發 Reflow?
- 新增 / 刪除 DOM 節點
- 改變元素尺寸:
width、height、padding、margin、border - 改變元素位置:
top、left、position(相對定位切換) - 改變字體大小 / 行高
- 視窗 resize、字型載入完成
- 讀取會強制同步 Layout 的屬性:
offsetWidth、offsetHeight、clientTop、scrollTop、getBoundingClientRect()、getComputedStyle()
哪些操作只會觸發 Repaint?
color、background-color、visibility、outline、box-shadow(部分情況)
如何優化?
批次修改 DOM / 樣式
- 多次修改樣式時,改用
class一次切換,或先display: none再操作完再顯示。 - 使用
DocumentFragment或cloneNode離線處理 DOM,最後一次插入。
- 多次修改樣式時,改用
避免 Layout Thrashing(強制同步佈局)
- 不要在迴圈中交替「寫入樣式」與「讀取幾何屬性」,先讀後寫。
// Bad:每次迴圈都觸發 reflow for (const el of items) { el.style.width = el.offsetWidth + 10 + 'px'; } // Good:先讀後寫 const widths = items.map(el => el.offsetWidth); items.forEach((el, i) => el.style.width = widths[i] + 10 + 'px');使用
transform與opacity做動畫- 這兩個屬性不觸發 Layout 與 Paint,只走 Composite(由 GPU 合成),效能最好。
提升為合成層(Composite Layer)
- 使用
will-change: transform、transform: translateZ(0)讓元素獨立合成,避免影響其他元素。
- 使用
避免使用 table 佈局
<table>中任何一個元素變動會導致整個 table reflow。
大量動畫 / 滾動事件搭配
requestAnimationFrame- 將視覺更新排進下一幀,避免一幀內重複 reflow。
虛擬 DOM / 框架 diff
- React、Vue 透過 diff 批次更新,減少 DOM 操作次數。
小結
| 類型 | 觸發時機 | 成本 |
|---|---|---|
| Reflow | 幾何變化 | 高(重算 Layout) |
| Repaint | 外觀變化 | 中 |
| Composite | transform / opacity | 低(GPU) |
優化核心:減少 Reflow 次數、改用 transform/opacity 做動畫、避免強制同步佈局。
✦ AI 模擬面試
輸入你的答案,AI 即時分析精準度與改進空間
登入後即可使用 AI 評分
