關(guān)鍵渲染路徑(CRP)
瀏覽器渲染網(wǎng)頁是一個(gè)復(fù)雜的過程,這個(gè)過程涉及關(guān)鍵渲染路徑(CRP)。CRP 包含從獲取 HTML、CSS 和 JavaScript 資源開始,到最終將像素呈現(xiàn)在屏幕上的一系列關(guān)鍵步驟,這些步驟包括解析 HTML、解析 CSS、布局以及繪制等多個(gè)環(huán)節(jié),
MDN上的描述
瀏覽器開始解析 HTML,將收到的數(shù)據(jù)轉(zhuǎn)換為 DOM 樹。當(dāng)瀏覽器每次發(fā)現(xiàn) DOM 樹包含外部資源就會(huì)初始化其請(qǐng)求(無論是樣式、腳本或者嵌入的圖片引用)。有時(shí)這些請(qǐng)求會(huì)阻塞,意味著解析剩下的 HTML 會(huì)被終止,直到前面這些重要的資源得到處理。瀏覽器接著解析 HTML,發(fā)送請(qǐng)求并構(gòu)造 DOM,直到 HTML 的文件結(jié)尾,此時(shí)就會(huì)開始構(gòu)造 CSSOM。等到 DOM 和 CSSOM 完成之后,瀏覽器構(gòu)造渲染樹,計(jì)算所有可見內(nèi)容的樣式。一旦渲染樹完成,布局就會(huì)開始,定義所有渲染樹元素的位置和大小。在布局完成后,頁面被渲染完成(被繪制到屏幕上)。
瀏覽器渲染流程
得到HTML
瀏覽器接收到HTTP響應(yīng)的數(shù)據(jù)包,這些數(shù)據(jù)包包含HTML,CSS,JavaScript以及可能的圖片和其他資源。
解析HTML
意義:
- 由于字符串難以進(jìn)行操作,瀏覽器首先會(huì)將 HTML 字符串解析成 DOM 樹和 CSSOM 樹這種容易操作的對(duì)象結(jié)構(gòu),也提供了 JS 操作這兩顆樹的能力。
- 構(gòu)建 CSSOM 樹主要是使得瀏覽器能夠更高效地理解和處理樣式之間的關(guān)系。
實(shí)現(xiàn):
- 構(gòu)建 DOM 樹:瀏覽器首先會(huì)解析 HTML 文檔,構(gòu)建一個(gè) DOM(文檔對(duì)象模型)樹。每個(gè) HTML 元素都會(huì)成為樹中的一個(gè)節(jié)點(diǎn)。
- 構(gòu)建 CSSOM 樹:DOM 樹構(gòu)建完成一部分后開始構(gòu)建 CSSOM 樹,當(dāng)瀏覽器開始解析 HTML 時(shí),它也會(huì)同時(shí)發(fā)現(xiàn)并請(qǐng)求 CSS 資源。一旦 CSS 文件開始被接收并解析,或者當(dāng)遇到內(nèi)聯(lián) CSS 時(shí),瀏覽器就會(huì)開始構(gòu)建 CSSOM 樹。
解析CSS(樣式計(jì)算)
意義:
- 樣式控制和動(dòng)態(tài)更新:
- JavaScript 可以通過操作 CSSOM 樹來動(dòng)態(tài)修改元素的樣式。
- 渲染樹合成基礎(chǔ):
- CSS 計(jì)算得到的每個(gè)元素的樣式信息是構(gòu)建渲染樹的重要基礎(chǔ)。
過程:
- 樣式收集和處理:
- 瀏覽器首先收集來自不同來源的樣式信息,包括內(nèi)聯(lián)樣式
<style>標(biāo)簽內(nèi)的樣式以及外部 CSS 文件。 - 對(duì)于
<style>標(biāo)簽內(nèi)的樣式和外部 CSS 文件,瀏覽器會(huì)按照它們?cè)?HTML 文檔中的加載順序進(jìn)行解析
- 瀏覽器首先收集來自不同來源的樣式信息,包括內(nèi)聯(lián)樣式
- 標(biāo)記化和語法分析
- 對(duì)收集到的 CSS 樣式內(nèi)容進(jìn)行標(biāo)記化,將其分解成一個(gè)個(gè)的標(biāo)記;
- 構(gòu)建 CSSOM 樹
- 瀏覽器根據(jù) CSS 的層疊規(guī)則來計(jì)算每個(gè)元素最終的樣式
- 依次為樹中的每個(gè)節(jié)點(diǎn)計(jì)算出它最終的樣式,稱之為 Computed Style
注意:CSS 是渲染阻塞的:瀏覽器會(huì)阻塞頁面渲染直到它接收和執(zhí)行了所有的 CSS。CSS 是渲染阻塞是因?yàn)橐?guī)則可以被覆蓋,所以直至 CSSOM 構(gòu)建完成之前,內(nèi)容都不能被渲染。
布局
意義:
- 渲染樹的構(gòu)建是將 DOM 樹和 CSSOM 樹結(jié)合的過程,
- 布局取決于屏幕的尺寸。布局這個(gè)步驟決定了在哪里和如何在頁面上放置元素,決定了每個(gè)元素的寬和高,以及他們之間的相關(guān)性。
過程:
- 生成布局樹(渲染樹)
- 瀏覽器檢查每個(gè)節(jié)點(diǎn),從 DOM 樹的根節(jié)點(diǎn)開始,并且決定哪些 CSS 規(guī)則被添加。渲染樹只包含了可見內(nèi)容。 在DOM樹上不可見的元素,最后都不會(huì)出現(xiàn)在布局樹上。
- 計(jì)算布局(回流):
- 一旦渲染樹構(gòu)建完成,瀏覽器會(huì)計(jì)算每個(gè)節(jié)點(diǎn)的幾何信息,包括位置和大小,這個(gè)過程稱為布局(或回流)。
分層(繪制)
意義:
- 分層的好處在于,將來某一個(gè)層改變后,僅會(huì)對(duì)該層進(jìn)行后續(xù)處理,只需要更新特定的層,而不是整個(gè)頁面,減少了重繪的范圍。
過程:
- 對(duì)渲染樹進(jìn)行分層:
- 渲染主線程會(huì)使用一套復(fù)雜的策略對(duì)整個(gè)布局樹(渲染樹)進(jìn)行分層。例如,具有 3D 變換、視頻元素或者使用了硬件加速的元素通常會(huì)被單獨(dú)分層。
- 生成繪制列表:
- 渲染主線程會(huì)根據(jù)計(jì)算好的樣式和布局信息,為每個(gè)圖層單獨(dú)生成繪制指令集,這些繪制指令會(huì)告訴瀏覽器的圖形處理單元(GPU)如何將元素繪制到屏幕上。
分塊
意義:
- 分塊就是將頁面劃分成多個(gè)小的矩形區(qū)域(塊),如果一次性處理整個(gè)頁面的繪制,會(huì)消耗大量的系統(tǒng)資源并且可能導(dǎo)致性能問題。分塊就是將頁面劃分減少繪制時(shí)的消耗。
過程:
- 瀏覽器(合成線程)對(duì)每個(gè)圖層進(jìn)行分塊,根據(jù)布局信息來確定哪些塊是當(dāng)前可見的或者即將可見的(考慮到滾動(dòng)等情況)。對(duì)于每個(gè)塊,會(huì)獨(dú)立地進(jìn)行繪制操作。
光柵化
意義:
- 光柵化就是將矢量圖形(如由 HTML 和 CSS 定義的各種頁面元素形狀)轉(zhuǎn)換為位圖(由像素組成的圖像)的過程,這是為了讓圖形能夠在以像素為基礎(chǔ)的顯示器上正確顯示。
過程:
- 確定光柵化區(qū)域:
- 瀏覽器首先需要確定哪些區(qū)域的網(wǎng)頁元素需要進(jìn)行光柵化。這通常是基于布局和分層信息來判斷的。
- 矢量圖形轉(zhuǎn)換為位圖:
- 對(duì)于需要光柵化的元素,瀏覽器將其矢量圖形表示(如根據(jù) CSS 樣式定義的形狀、文本的字體輪廓等)按照一定的算法轉(zhuǎn)換為位圖。
- 像素?cái)?shù)據(jù)處理和優(yōu)化:
合成
意義:
- 當(dāng)文檔的各個(gè)部分以不同的層繪制,相互重疊時(shí),必須進(jìn)行合成,以確保它們以正確的順序繪制到屏幕上,并正確顯示內(nèi)容。
- 實(shí)現(xiàn)高效更新和動(dòng)畫效果:
- 某些元素的變化可能只涉及到特定的層,通過合成,瀏覽器可以只更新受影響的層。
實(shí)現(xiàn):
- 生成合成指令
- 合成線程根據(jù)每個(gè)層的信息(包括層的位置、大小、透明度等)以及它們之間的關(guān)系,生成一系列的合成指令。這些指令類似于一個(gè) “藍(lán)圖”,告訴瀏覽器如何將各個(gè)層的內(nèi)容進(jìn)行組合和繪制。
- 提交給 GPU 進(jìn)行處理:
- 合成線程將生成的合成指令提交給 GPU 進(jìn)程。GPU 進(jìn)程接收到指令后,會(huì)根據(jù)指令中的信息進(jìn)行具體的圖形處理操作。
- 完成屏幕成像:
- GPU 完成合成操作后,會(huì)產(chǎn)生系統(tǒng)調(diào)用,將合成后的圖像數(shù)據(jù)提交給 GPU 硬件,最終完成在屏幕上的成像顯示。
各個(gè)步驟輸入輸出
每個(gè)階段都有明確的輸入輸出,上一個(gè)階段的輸出會(huì)成為下一個(gè)階段的輸入。
| 輸入 | 輸出 | |
|---|---|---|
| 解析 HTML 與 CSS | HTML 文檔內(nèi)容(字節(jié)) | DOM 樹 |
| 樣式計(jì)算 | DOM 樹 | DOM 樹和 CSSOM 樹 |
| 布局 | DOM 樹和 CSSOM 樹 | 渲染樹 |
| 分層 | 渲染樹 | 分層后的結(jié)構(gòu) |
| 分塊 | 分層后的結(jié)構(gòu) | 矢量圖形信息 |
| 光柵化 | 矢量圖形信息 | 每個(gè)塊的位圖(像素矩陣) |
| 合成 | 位圖數(shù)據(jù) | 最終合成后的圖像數(shù)據(jù) |