關鍵渲染路徑(CRP)
瀏覽器渲染網頁是一個複雜的過程,這個過程涉及關鍵渲染路徑(CRP)。CRP 包含從獲取 HTML、CSS 和 JavaScript 資源開始,到最終將畫素呈現在螢幕上的一系列關鍵步驟,這些步驟包括解析 HTML、解析 CSS、佈局以及繪製等多個環節,
MDN上的描述
瀏覽器開始解析 HTML,將收到的資料轉換為 DOM 樹。當瀏覽器每次發現 DOM 樹包含外部資源就會初始化其請求(無論是樣式、指令碼或者嵌入的圖片引用)。有時這些請求會阻塞,意味著解析剩下的 HTML 會被終止,直到前面這些重要的資源得到處理。瀏覽器接著解析 HTML,傳送請求並構造 DOM,直到 HTML 的檔案結尾,此時就會開始構造 CSSOM。等到 DOM 和 CSSOM 完成之後,瀏覽器構造渲染樹,計算所有可見內容的樣式。一旦渲染樹完成,佈局就會開始,定義所有渲染樹元素的位置和大小。在佈局完成後,頁面被渲染完成(被繪製到螢幕上)。
瀏覽器渲染流程
得到HTML
瀏覽器接收到HTTP響應的資料包,這些資料包包含HTML,CSS,JavaScript以及可能的圖片和其他資源。
解析HTML
意義:
- 由於字串難以進行操作,瀏覽器首先會將 HTML 字串解析成 DOM 樹和 CSSOM 樹這種容易操作的物件結構,也提供了 JS 操作這兩顆樹的能力。
- 構建 CSSOM 樹主要是使得瀏覽器能夠更高效地理解和處理樣式之間的關係。
實現:
- 構建 DOM 樹:瀏覽器首先會解析 HTML 文件,構建一個 DOM(文件物件模型)樹。每個 HTML 元素都會成為樹中的一個節點。
- 構建 CSSOM 樹:DOM 樹構建完成一部分後開始構建 CSSOM 樹,當瀏覽器開始解析 HTML 時,它也會同時發現並請求 CSS 資源。一旦 CSS 檔案開始被接收並解析,或者當遇到內聯 CSS 時,瀏覽器就會開始構建 CSSOM 樹。
解析CSS(樣式計算)
意義:
- 樣式控制和動態更新:
- JavaScript 可以透過操作 CSSOM 樹來動態修改元素的樣式。
- 渲染樹合成基礎:
- CSS 計算得到的每個元素的樣式資訊是構建渲染樹的重要基礎。
過程:
- 樣式收集和處理:
- 瀏覽器首先收集來自不同來源的樣式資訊,包括內聯樣式
<style>
標籤內的樣式以及外部 CSS 檔案。 - 對於
<style>
標籤內的樣式和外部 CSS 檔案,瀏覽器會按照它們在 HTML 文件中的載入順序進行解析
- 瀏覽器首先收集來自不同來源的樣式資訊,包括內聯樣式
- 標記化和語法分析
- 對收集到的 CSS 樣式內容進行標記化,將其分解成一個個的標記;
- 構建 CSSOM 樹
- 瀏覽器根據 CSS 的層疊規則來計算每個元素最終的樣式
- 依次為樹中的每個節點計算出它最終的樣式,稱之為 Computed Style
注意:CSS 是渲染阻塞的:瀏覽器會阻塞頁面渲染直到它接收和執行了所有的 CSS。CSS 是渲染阻塞是因為規則可以被覆蓋,所以直至 CSSOM 構建完成之前,內容都不能被渲染。
佈局
意義:
- 渲染樹的構建是將 DOM 樹和 CSSOM 樹結合的過程,
- 佈局取決於螢幕的尺寸。佈局這個步驟決定了在哪裡和如何在頁面上放置元素,決定了每個元素的寬和高,以及他們之間的相關性。
過程:
- 生成佈局樹(渲染樹)
- 瀏覽器檢查每個節點,從 DOM 樹的根節點開始,並且決定哪些 CSS 規則被新增。渲染樹只包含了可見內容。 在DOM樹上不可見的元素,最後都不會出現在佈局樹上。
- 計算佈局(迴流):
- 一旦渲染樹構建完成,瀏覽器會計算每個節點的幾何資訊,包括位置和大小,這個過程稱為佈局(或迴流)。
分層(繪製)
意義:
- 分層的好處在於,將來某一個層改變後,僅會對該層進行後續處理,只需要更新特定的層,而不是整個頁面,減少了重繪的範圍。
過程:
- 對渲染樹進行分層:
- 渲染主執行緒會使用一套複雜的策略對整個佈局樹(渲染樹)進行分層。例如,具有 3D 變換、影片元素或者使用了硬體加速的元素通常會被單獨分層。
- 生成繪製列表:
- 渲染主執行緒會根據計算好的樣式和佈局資訊,為每個圖層單獨生成繪製指令集,這些繪製指令會告訴瀏覽器的圖形處理單元(GPU)如何將元素繪製到螢幕上。
分塊
意義:
- 分塊就是將頁面劃分成多個小的矩形區域(塊),如果一次性處理整個頁面的繪製,會消耗大量的系統資源並且可能導致效能問題。分塊就是將頁面劃分減少繪製時的消耗。
過程:
- 瀏覽器(合成執行緒)對每個圖層進行分塊,根據佈局資訊來確定哪些塊是當前可見的或者即將可見的(考慮到滾動等情況)。對於每個塊,會獨立地進行繪製操作。
光柵化
意義:
- 光柵化就是將向量圖形(如由 HTML 和 CSS 定義的各種頁面元素形狀)轉換為點陣圖(由畫素組成的影像)的過程,這是為了讓圖形能夠在以畫素為基礎的顯示器上正確顯示。
過程:
- 確定光柵化區域:
- 瀏覽器首先需要確定哪些區域的網頁元素需要進行光柵化。這通常是基於佈局和分層資訊來判斷的。
- 向量圖形轉換為點陣圖:
- 對於需要光柵化的元素,瀏覽器將其向量圖形表示(如根據 CSS 樣式定義的形狀、文字的字型輪廓等)按照一定的演算法轉換為點陣圖。
- 畫素資料處理和最佳化:
合成
意義:
- 當文件的各個部分以不同的層繪製,相互重疊時,必須進行合成,以確保它們以正確的順序繪製到螢幕上,並正確顯示內容。
- 實現高效更新和動畫效果:
- 某些元素的變化可能只涉及到特定的層,透過合成,瀏覽器可以只更新受影響的層。
實現:
- 生成合成指令
- 合成執行緒根據每個層的資訊(包括層的位置、大小、透明度等)以及它們之間的關係,生成一系列的合成指令。這些指令類似於一個 “藍圖”,告訴瀏覽器如何將各個層的內容進行組合和繪製。
- 提交給 GPU 進行處理:
- 合成執行緒將生成的合成指令提交給 GPU 程序。GPU 程序接收到指令後,會根據指令中的資訊進行具體的圖形處理操作。
- 完成螢幕成像:
- GPU 完成合成操作後,會產生系統呼叫,將合成後的影像資料提交給 GPU 硬體,最終完成在螢幕上的成像顯示。
各個步驟輸入輸出
每個階段都有明確的輸入輸出,上一個階段的輸出會成為下一個階段的輸入。
輸入 | 輸出 | |
---|---|---|
解析 HTML 與 CSS | HTML 文件內容(位元組) | DOM 樹 |
樣式計算 | DOM 樹 | DOM 樹和 CSSOM 樹 |
佈局 | DOM 樹和 CSSOM 樹 | 渲染樹 |
分層 | 渲染樹 | 分層後的結構 |
分塊 | 分層後的結構 | 向量圖形資訊 |
光柵化 | 向量圖形資訊 | 每個塊的點陣圖(畫素矩陣) |
合成 | 點陣圖資料 | 最終合成後的影像資料 |