程序員:HTML、CSS、JavaScript是如何變成頁面的?

從輸入HTML、CSS、JavaScript到瀏覽器渲染出我們預期的效果,渲染流程分為這幾個子階段:構建DOM樹、樣式計算、佈局階段、分層、繪製、分塊、光柵化和合成。

以下面這段html舉例講解這幾個過程:

//aa.html

<title>Title/<title>

<link>

hello

hi

<button>ok/<button>


//aa.css

#p-two {

font-size:2rem;

}


//aa.js

$("#p-three").bind("click", function() {

$("#p-three").css("color", "blue");

});


構建DOM樹

因為瀏覽器⽆法直接理解和使⽤HTML,所以需要將HTML轉換為瀏覽器能夠理解的結構——DOM樹。

程序員:HTML、CSS、JavaScript是如何變成頁面的?

樣式計算

樣式計算的⽬的是為了計算出DOM節點中每個元素的具體樣式,分為三個步驟:

  1. 把CSS轉換為瀏覽器能夠理解的結構—styleSheets
程序員:HTML、CSS、JavaScript是如何變成頁面的?

2.轉換樣式表中的屬性值,使其標準化,如:

font-size:2em->font-size:32px

p{color:blue}->p{color:rgb(0,0,255)}

div{font-weight:bold}->div{font-weight:700}

3.計算出DOM樹中每個節點的具體樣式,最終輸出的內容是每個DOM節點的樣式,並被保存在ComputedStyle的結構內。

程序員:HTML、CSS、JavaScript是如何變成頁面的?

程序員:HTML、CSS、JavaScript是如何變成頁面的?

佈局階段

現在,以及有了DOM樹和DOM樹中元素的樣式,但還不足以顯示頁面,因為還不知道DOM元素的幾何位置信息,佈局階段就是需要計算出DOM樹中元素的幾何位置,包括以下幾個步驟:

創建佈局樹

DOM樹中包含很多不可見的標籤,比如某個標籤使用了屬性"display:none"。所以在顯示之前,還要額外地構建一棵只包含可見元素的佈局樹,瀏覽器創建佈局樹的大致流程為:遍歷DOM樹中所有可見節點,並加入佈局樹中,忽略不可見節點。

佈局計算

計算每個元素的幾何座標位置,並將這些信息保存在佈局樹中。

小結前三個階段:在HTML頁面內容被提交給瀏覽器渲染引擎後,渲染引擎首先將HTML解析為瀏覽器可以理解的DOM;然後根據CSS樣式表,計算出DOM數所有節點的樣式;接著又計算每個元素的幾何座標位置,並將這些信息保存在佈局樹中。

分層

有了每個元素的樣式和位置信息,但還是不能開始著手繪製頁面,因為頁面中還有很多複雜的效果,如3D變化、頁面滾動等,為了實現這些效果,渲染引擎還需要為特定節點生成專門的圖層,並生成一顆對應的圖層樹,即有些元素實際上是被分成了很多層,這些圖層疊加後合成了最終的頁面。只要滿足下面兩個條件之一的元素就會可以生成一個對應的圖層:

擁有層疊上下文屬性的元素會被提升為單獨的一層

程序員:HTML、CSS、JavaScript是如何變成頁面的?

從圖中可以看出,明確定位屬性的元素、定義透明屬性的元素、使用CSS濾鏡的元素等,都擁有層疊上下文屬性。

需要裁減的地方也會被創建為圖層

舉例:在css中指定了一個div大width和height屬性後,如果div子元素p標籤的文字內容超過了widthheight大小,就會只把能在widthheight面積內能顯示的內容顯示出來,其他內容被裁減掉了。

圖層繪製

有了圖層樹之後,渲染引擎會對圖層樹中的每個圖層進行繪製。圖層繪製階段,就是輸入各種繪製指令組成的列表(注意,這個階段還不是真正地著手繪製)。

在原aa.html文件中添加代碼

pp
下圖中,紅色區域就是繪製列表,粉色區域顯示的是繪製過程,可點擊任何一個繪製過程查看。
程序員:HTML、CSS、JavaScript是如何變成頁面的?

分塊和柵格化操作

繪製列表只是用來記錄繪製順序和繪製指令,而實際繪製操作是由渲染引擎中的合成線程來完成的。當圖層的繪製列表準備好之後,主線程就會把繪製列表提交給合成線程。合成線程會將圖層劃分為圖塊,視口(就是當前窗口可見的區域)附近的圖塊優先生產位圖,生產位圖的操作實際由柵格化來執行(柵格化的具體含義可自行百度)。渲染進維護了一個柵格化線程池,所有的圖塊柵格化都是在線程池內執行的,該過程會使用GPU來加速,生產的位圖被保存在GPU內存中。

合成和顯示

當所有圖塊都被光柵化(柵格化)後,合成線程就會生成繪製圖塊的命令,然後該命令提交給瀏覽器進程(這裡簡單說下Chrome瀏覽器多進程架構,其將瀏覽器分為:渲染進程、插件進程、GPU進程和瀏覽器主進程,瀏覽器主進程包含UI模塊、網絡模塊、文件模塊等),瀏覽器進程將其頁面內容繪製到內存中,最後再將內存內容顯示在屏幕上。

至此,HTML+CSS+JavaScript就能生成我們所看見的頁面了。

總結

一個完整的渲染流程大致如下:

  • 渲染進程將HTML內存轉換為瀏覽器能夠識別的DOM數據結構
  • 渲染引擎將CSS樣式錶轉換為瀏覽器能夠識別的sytleSheets,計算出DOM節點的樣式
  • 創建佈局樹,包括可見元素以及元素的位置計算
  • 渲染引擎為達到分層條件的節點生成對應的圖層,所有圖層組合成一顆圖層樹
  • 生成圖層的繪製列表,記錄繪製順序和繪製指令
  • 有合成線程進行柵格化操作,將圖層劃分為圖塊,渲染進程把生成的圖塊發送給GPU,在GPU中執行生成圖塊的位圖
  • 所有圖塊被柵格化之後,合成線程會發送繪製圖塊的命令給瀏覽器進程,在瀏覽器進程中進行圖塊合成並最紅顯示到屏幕上


分享到:


相關文章: