HTML CSS JavaScript數據經過渲染模塊的處理,最終輸出為屏幕上的像素。這中間的渲染模塊就是我們今天要討論的主題。
- 構建DOM樹
- 樣式計算
- 布局階段
- 分層
- 圖層繪制
- 柵格化操作
- 合成與顯示
1. 構建DOM樹
因為瀏覽器無法直接理解和使用 HTML,所以需要將 HTML 轉換為瀏覽器能夠理解的結構——DOM 樹。
- 輸入:HTML文件
- 處理過程:HTML解析器解析
- 輸出:樹狀結構的DOM樹
打開 Chrome 的開發者工具,選擇
Console
標簽打開控制臺,在控制臺輸入document
并回車,這樣就可以看到一個完成的DOM樹結構
2. 樣式計算
- 輸入:CSS文本
-
處理過程:渲染引擎根據分三步完成CSS的解析
1.document.styleSheets;
2.屬性值標準化;
3.根據繼承規則和層疊規則進行計算) - 輸出:每個DOM節點的樣式并被保存在ComputedStyle結構內
- 把css轉換成瀏覽器能夠理解的結構 -- styleSheets
打開 Chrome 的開發者工具,選擇
Console
標簽打開控制臺,在控制臺輸入document.styleSheets
并回車,這樣就可以看到styleSheets的結構
-
轉換樣式表中的屬性值,使其標準化
標準化樣式的屬性值 - 計算出DOM樹中每個節點的具體樣式
-
繼承規則:DOM節點能繼承父節點的可繼承樣式
樣式的繼承示意圖 -
層疊規則:提供了如何合并來自多個源的屬性值的算法
DOM元素樣式計算最終結果
3. 布局階段
計算 DOM 樹中可見元素的幾何位置,該計算過程叫做布局。布局階段需要完成兩個任務:創建布局樹和布局計算。
- 輸入:DOM樹 + ComputedStyle結構
- 處理過程:布局處理
- 輸出:布局樹
-
創建布局樹
所有不可見元素都不會包含在布局樹中。
布局樹構造示意圖 布局計算
計算布局樹節點的坐標位置并更新布局樹 - 該過程比較復雜此處不做展開。
4. 分層
渲染引擎會為特定的節點生成專用的圖層并生成一顆對應的圖層樹。
- 輸入:布局樹
- 處理過程:渲染引擎處理
- 輸出:圖層樹
打開 Chrome 的開發者工具,選擇
Layers
標簽就可以看到可視化頁面的分層情況
并不是布局樹的每個節點都對應一個圖層,如果一個節點沒有對應的層,那么這個節點就從屬于父節點的層。
需要滿足什么條件,渲染引擎才會為特定的節點創建新的圖層呢?
滿足以下條件之一:
- 擁有層疊上下文屬性的元素會被提升為單獨的一層
- 需要剪裁的地方也會被創建為圖層
5. 圖層繪制
在完成圖層樹的構建之后,渲染引擎會對圖層樹中的每個圖層進行繪制。
渲染引擎會把圖層的繪制拆分成很多小的繪制指令,然后再把這些指令按順序組成一個繪制列表。
柵格化操作
實際上繪制操作是有渲染引擎中的合成線程來完成的。
主線程會把繪制列表提交給合成線程。
合成線程會將圖層劃分為圖塊(tile),大小通常為256x256或512x512.
合成線程按照視口附近的圖塊來優先生成位圖。
所謂柵格化就是指將圖塊轉換為位圖
6. 合成與顯示
一旦所有圖塊都被柵格化,合成線程就會生成一個繪制圖塊的命令“DrawQuad”,然后將該命令提交給瀏覽器進程。
瀏覽器進程接收合成線程發過來的“DrawQuad”命令然后根據該命令將頁面內容繪制到內存中,最后將內存顯示在屏幕上。
總結
結合上圖,一個完整的渲染流程大致可總結為如下:
- 渲染進程將 HTML 內容轉換為能夠讀懂的 DOM 樹結構。
- 渲染引擎將 CSS 樣式表轉化為瀏覽器可以理解的 styleSheets,計算出 DOM 節點的樣式。
- 創建布局樹,并計算元素的布局信息。
- 對布局樹進行分層,并生成分層樹。
- 為每個圖層生成繪制列表,并將其提交到合成線程。
- 合成線程將圖層分成圖塊,并在光柵化線程池中將圖塊轉換成位圖。
- 合成線程發送繪制圖塊命令 DrawQuad 給瀏覽器進程。
- 瀏覽器進程根據 DrawQuad 消息生成頁面,并顯示到顯示器上。
文章內容參考極客時間 李兵老師的瀏覽器工作原理與實踐課程。