Featured image of post 優化瀏覽器渲染管道(關鍵路徑)Featured image of post 優化瀏覽器渲染管道(關鍵路徑)

優化瀏覽器渲染管道(關鍵路徑)

透過防止佈局顛簸和優先考慮渲染阻塞腳本位置來最大限度地縮短啟動時間。

介紹

關鍵渲染路徑 (CRP) 是瀏覽器執行的將 HTML、CSS 和 JavaScript 轉換為螢幕上可見像素的步驟序列。優化此管道直接影響第一內容繪製 (FCP)最大內容繪製 (LCP)。本文詳細介紹了每個 CRP 階段——DOM 構建、CSSOM 構建、渲染樹、佈局、繪製和合成——並提供了可行的最佳化策略。


第一階段:DOM 構建

當瀏覽器接收到 HTML 位元組時,它:

  1. 位元組→字元:將原始位元組解碼為字符
  2. 標記化:將字元轉換為標記(StartTagEndTag 等)
  3. Lexing:將令牌轉換為節點
  4. DOM Tree:建立保留父子關係的節點樹
<!-- This HTML produces a DOM tree with html > head + body > h1 + p -->
<!DOCTYPE html>
<html>
<head><title>Page</title></head>
<body>
  <h1>Hello</h1>
  <p>World</p>
</body>
</html>

最佳化:最小化 HTML 大小,透過正確的伺服器配置儘早交付,並使用 串流(例如 Transfer-Encoding: chunked)。


第 2 階段:CSSOM 構建

預設情況下,CSS 是渲染阻塞的。瀏覽器在渲染之前必須下載並解析所有CSS。 CSS 位元組與 HTML 經歷相同的轉換管道,產生 CSS 物件模型 (CSSOM)

body { font-size: 16px; }
h1 { color: blue; }

每個 CSS 規則都與選擇器進行匹配,並在此階段計算特異性。

最佳化:

  • 直接在 <head> 中內嵌關鍵 CSS 以取得首頁內容
  • 使用 media="print"loading="lazy" 延遲非關鍵 CSS
  • 縮小並使用 tree-shaking 刪除未使用的 CSS

第三階段:渲染樹

渲染樹結合了 DOM 和 CSSOM — 它只包含可見元素。排除具有 display: none<head> 子元素的元素。每個渲染樹節點都包含其計算的樣式。

DOM       CSSOM
 |          |
 +----+-----+
      |
  Render Tree
 (visible nodes + computed styles)

第四階段:佈局(回流焊接)

瀏覽器計算每個渲染樹節點的幾何(位置和大小)。這是從視窗開始的自上而下傳遞。具有基於百分比的寬度、flexboxgrid 的元素要求瀏覽器計算相對於其容器的大小。

佈局抖動的原因

重複強制同步佈局 - 在編寫樣式後讀取佈局屬性(例如 offsetHeight) - 導致瀏覽器在單一框架中多次重新計算佈局

// ❌ Bad: Forces layout on each iteration
for (let i = 0; i < boxes.length; i++) {
  const width = box.offsetWidth;   // reads (triggers layout)
  box.style.width = (width + 10) + 'px';  // writes
}
// ✅ Good: Batch reads, then batch writes
const widths = boxes.map(b => b.offsetWidth); // reads
boxes.forEach((b, i) => b.style.width = (widths[i] + 10) + 'px'); // writes

最佳化:

  • 先讀取佈局屬性,然後寫入
  • 使用 transformopacity 進行動畫(僅限合成器)
  • 避免複雜的 CSS 選擇器在回流時觸發選擇器匹配
  • 使用 contain: layout style paint 隔離子樹

第五階段:油漆

瀏覽器將像素填入圖層中—文字、顏色、圖像、邊框、陰影。這是昂貴的,因為它涉及光柵化。單獨的合成器層上的元素可以獨立繪製。

油漆觸發器

  • 改為 colorbackground-colorvisibilityoutline
  • 添加陰影或文字裝飾

第六階段:複合

瀏覽器將繪製的圖層合併到 GPU 上的最終畫面。相對於佈局和繪製來說,合成成本較低。關鍵是盡量減少佈局和繪製工作,以便大多數更改只需要合成。

僅限合成器的屬性

物業觸發器佈局觸發油漆僅合成器
佔位符_0沒有沒有是的
佔位符_0沒有沒有是的
佔位符_0是的是的沒有
佔位符_0是的是的沒有

阻塞資源與非阻塞資源

資源預設行為最佳化
CSS (<link>)渲染阻塞內嵌關鍵,延遲非關鍵
JS <script>解析器阻塞 (DOM)使用 asyncdefer
JS defer非阻塞,在 HTML 解析後執行訂單已保留
JS async非阻塞,下載時執行無訂單保證
<!-- ✅ Best practices -->
<script async src="analytics.js"></script>
<script defer src="app.js"></script>
<link rel="stylesheet" href="critical.css" />
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'" />

衡量 CRP 績效

Lighthouse 提供針對 CRP 的稽核:

  • 消除渲染阻塞資源 — 辨識阻塞 CSS/JS
  • 推遲螢幕外圖像 — 減少繪畫區域
  • 最小化主執行緒工作 - 辨識長任務
  • 減少 JavaScript 執行時間 — 有助於解析器阻塞腳本

運行:npx lighthouse https://example.com --preset=desktop


結論

優化關鍵渲染路徑需要了解 DOM/CSSOM 構造、渲染樹形成、佈局、繪製和合成的順序性質。關鍵策略包括內聯關鍵 CSS、對腳本使用 async/defer、透過批次 DOM 讀/寫避免佈局抖動,以及優先使用僅限合成器的動畫屬性。定期 Lighthouse 審核有助於識別 CRP 瓶頸並指導持續改進。