建構物件模型

Ilya Grigorik
Ilya Grigorik

發布日期:2014 年 3 月 31 日

瀏覽器必須先建構 DOM 和 CSSOM 樹狀結構,才能轉譯網頁。因此,我們需要確保盡快將 HTML 和 CSS 傳送至瀏覽器。

摘要

  • 位元組 → 字元 → 符記 → 節點 → 物件模型。
  • HTML 標記會轉換為文件物件模型 (DOM);CSS 標記會轉換為 CSS 物件模型 (CSSOM)。
  • DOM 和 CSSOM 是獨立的資料結構。
  • Chrome 開發人員工具「效能」面板可讓我們擷取及檢查 DOM 和 CSSOM 的建構和處理成本。

文件物件模型 (DOM)

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link href="style.css" rel="stylesheet" />
    <title>Critical Path</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg" /></div>
  </body>
</html>

試用

請從最簡單的情況開始:純 HTML 網頁,其中包含一些文字和單一圖片。瀏覽器如何處理這個網頁?

DOM 建構程序

  1. 轉換:瀏覽器會從磁碟或網路讀取 HTML 的原始位元組,然後根據檔案的指定編碼 (例如 UTF-8) 將其轉換為個別字元。
  2. 符記化:瀏覽器會將字元字串轉換為不同的符記 (如 W3C HTML5 標準所指定,例如 <html><body>),以及其他尖括號內的字串。每個符記都有特殊含義和一組規則。
  3. Lexing:產生的符記會轉換為「物件」,定義其屬性和規則。
  4. DOM 建構:最後,由於 HTML 標記定義了不同標記之間的關係 (部分標記包含在其他標記中),因此建立的物件會在樹狀資料結構中連結,同時擷取原始標記中定義的父項/子項關係:HTML 物件是 body 物件的父項,bodyparagraph 物件的父項,直到整個文件的表示法建構完成為止。

DOM 樹狀結構

整個程序的最終輸出內容是簡易網頁的文件物件模型 (DOM),瀏覽器會使用這個模型處理網頁的所有後續作業。

瀏覽器每次處理 HTML 標記時,都會執行先前定義的所有步驟:將位元組轉換為字元、識別符記、將符記轉換為節點,以及建構 DOM 樹狀結構。整個程序可能需要一些時間,尤其是當我們需要處理大量 HTML 時。

在開發人員工具中追蹤 DOM 建構

如果您開啟 Chrome 開發人員工具,並在網頁載入時記錄時間軸,就能看到執行此步驟所需的實際時間。在前述範例中,將一段 HTML 轉換為 DOM 樹狀結構所需的時間約為 5 毫秒。如果是較大的網頁,這項程序可能需要更長的時間。在建立流暢的動畫時,如果瀏覽器必須處理大量 HTML,這可能會成為瓶頸。

DOM 樹狀結構會擷取文件標記的屬性和關係,但不會告訴我們元素在算繪時的樣貌。這就是 CSSOM 的責任。

CSS 物件模型 (CSSOM)

在瀏覽器建構基本網頁的 DOM 時,遇到文件 <head> 中參照外部 CSS 樣式表單 style.css<link> 元素。系統預測需要此資源才能轉譯網頁,因此會立即調度此資源的要求,並傳回以下內容:

body {
  font-size: 16px;
}

p {
  font-weight: bold;
}

span {
  color: red;
}

p span {
  display: none;
}

img {
  float: right;
}

我們可以直接在 HTML 標記 (內嵌) 中宣告樣式,但將 CSS 與 HTML 分開,可讓我們將內容和設計視為不同的問題:設計師可處理 CSS,開發人員則可專注於 HTML 和其他問題。

與 HTML 一樣,我們需要將收到的 CSS 規則轉換為瀏覽器可理解及使用的內容。因此,我們重複 HTML 程序,但針對 CSS 而非 HTML:

CSSOM 建構步驟

CSS 位元組會轉換為字元、符記和節點,最後連結成稱為「CSS 物件模型」(CSSOM) 的樹狀結構:

CSSOM 樹狀結構

CSSOM 為何採用樹狀結構?在為網頁上的任何物件計算最終樣式組合時,瀏覽器會從適用於該節點的最一般規則開始 (例如,如果該節點是 body 元素的子項,則會套用所有 body 樣式),然後透過套用更明確的規則遞迴式精進已計算的樣式,也就是「依序套用」規則。

為讓您更清楚瞭解這項功能,請參考先前所述的 CSSOM 樹狀結構。放置在 body 元素內的 <span> 標記中,任何包含的文字都會顯示 16 像素的字型大小,並以紅色顯示文字 - font-size 指令會從 body 向下依序連結至 span。不過,如果 span 是段落 (p) 標記的子項,則不會顯示其內容。

另請注意,先前所述的樹狀結構並非完整的 CSSOM 樹狀結構,只會顯示我們決定在樣式表格中覆寫的樣式。每個瀏覽器都會提供一組預設樣式,也稱為「使用者代理程式樣式」,也就是我們未提供任何樣式時所看到的樣式。我們的樣式會覆寫這些預設樣式。

如要瞭解 CSS 處理作業所需的時間,您可以在 DevTools 中記錄時間軸,然後尋找「Recalculate Style」事件:與 DOM 剖析不同,時間軸不會顯示個別的「Parse CSS」項目,而是擷取剖析和 CSSOM 樹狀結構的資訊,並在這個事件下對計算樣式進行遞迴計算。

在開發人員工具中追蹤 CSSOM 建構作業

我們的瑣碎樣式表格需要約 0.6 毫秒的處理時間,並影響頁面上的八個元素,雖然影響不大,但仍會造成額外負擔。不過,這八個元素的來源為何?CSSOM 和 DOM 是獨立的資料結構!原來是瀏覽器隱藏了重要的步驟。接下來,我們將介紹轉譯樹狀結構,將 DOM 和 CSSOM 連結在一起。

意見回饋