建構物件模型

Ilya Grigorik
Ilya Grigorik

瀏覽器必須先建構 DOM 和 CSSOM 樹狀結構,才能轉譯網頁。因此,我們必須盡快將 HTML 和 CSS 提供給瀏覽器。

摘要

  • 位元組 → 字元 → 符記 → 節點 → 物件模型。
  • HTML 標記可轉換為 Document 物件模型 (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. 放出:發出的符記會轉換為「物件」,並定義其屬性和規則。
  4. DOM 結構:最後,由於 HTML 標記定義了不同標記 (某些標記包含在其他標記中) 之間的關係,因此建立的物件會在樹狀資料結構中連結,而此結構也會擷取原始標記中定義的父項與子項關係:HTML 物件是 body 物件的父項,bodyparagraph 物件的父項,依此類推。

DOM 樹狀結構

整個程序的最終結果是簡單網頁的 Document 物件模型 (DOM),瀏覽器會使用該模型進行頁面後續處理。

每次瀏覽器處理 HTML 標記時,都會進行上述所有步驟:將位元組轉換為字元、識別符記、將符記轉換為節點,以及建構 DOM 樹狀結構。這整個程序可能需要一段時間才能完成,尤其是處理大量 HTML 時。

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

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

DOM 樹狀結構會擷取文件標記的屬性和關係,但不會告訴我們元素轉譯後的樣子。這正是 CSSOM 的責任。

CSS 物件模型 (CSSOM)

瀏覽器建構簡易網頁的 DOM 時,在文件的 head 區段遇到一個連結標記,參照外部 CSS 樣式表:style.css。系統預期需要這項資源才能轉譯網頁,會立即分派對這項資源的要求,而要求會傳回以下內容:

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 元素的子項,就會套用所有主體樣式),然後套用更具體的規則,以遞迴方式調整運算樣式;也就是說,規則會「向下傳遞」。

為了更具體地說明,不妨考慮上方的 CSSOM 樹狀結構。<span> 標記中包含的所有文字,如果放在 body 元素中、字型大小為 16 像素,且含有紅色文字,則 font-size 指令會從 body 向下傳遞至 span。不過,如果 span 標記是段落 (p) 標記的子項,就不會顯示其內容。

此外,請注意,上述樹狀結構並非完整的 CSSOM 樹狀結構,只會顯示我們決定在樣式表中覆寫的樣式。每個瀏覽器都會提供一組預設樣式 (又稱為「使用者代理程式樣式」),也就是不提供任何自有樣式時會看到的樣式,而我們的樣式只是覆寫這些預設值。

如要確認 CSS 處理作業需要花費多久時間,您可以在開發人員工具中記錄時間軸,並尋找「重新計算樣式」事件:與 DOM 剖析不同,時間軸不會顯示個別的「Parse CSS」項目,而是擷取剖析和 CSSOM 樹狀結構結構,以及這個事件下的運算樣式遞迴計算。

開發人員工具中的追蹤 CSSOM 建構

處理流程需要約 0.6 毫秒,且會影響網頁上的八個元素,操作少之多,只是一次,不會造成任何影響。不過,八個元素是從哪裡來的?CSSOM 和 DOM 是獨立的資料結構!原來,瀏覽器隱藏了一個重要的步驟。接下來,我們來談談連結 DOM 與 CSSOM 的轉譯樹狀結構

意見回饋: