html,css,javascript是怎樣變成頁面的

瀏覽器是多進(jìn)程的,有瀏覽器主進(jìn)程,網(wǎng)絡(luò)進(jìn)程,渲染進(jìn)程,插件進(jìn)程等,在將html,css,javascript解析成一個頁面的時候,就需要多個進(jìn)程的分工合作。
當(dāng)瀏覽器接受到一個請求的響應(yīng)數(shù)據(jù),并且該數(shù)據(jù)的類型(content-type)為text/html,瀏覽器就會知道這是一個html頁面,于是網(wǎng)絡(luò)進(jìn)程就會將收到的數(shù)據(jù)交給渲染進(jìn)程后,就進(jìn)入了渲染階段,也就是在這一個階段,瀏覽器會根據(jù)數(shù)據(jù)生成一個新的頁面。
在執(zhí)行的過程中,會被分為很多個子階段,輸入的HTML經(jīng)過這些子階段,最后會輸出像素,這個處理過程叫做渲染流水線,按照渲染的時間順序,流水線可分為如下幾個子階段:
構(gòu)建DOM樹
網(wǎng)絡(luò)進(jìn)程交給渲染進(jìn)程的字節(jié)流渲染進(jìn)程是無法識別的,需要先轉(zhuǎn)化為dom樹,在渲染進(jìn)程內(nèi)部有個html解析器,就負(fù)責(zé)將字節(jié)流轉(zhuǎn)化為dom樹
解析器的工作過程
- 通過分詞器將字節(jié)流轉(zhuǎn)化為token,token分為tag token 和文本token,tag token又分為 starttag token 和 endtag token,比如
就是一個starttag token,就是一個endtag token
- 接著需要將token解析為dom節(jié)點,并將dom節(jié)點添加到dom樹中,這兩個過程是同步進(jìn)行的
- html解析器維護了一個token的棧結(jié)構(gòu),該token棧主要用來計算節(jié)點之間的父子關(guān)系,在第一個階段中生成的token會被按照順序壓入這個棧中,具體規(guī)則如下:
- 如果壓入到棧中的是StartTag Token,HTML 解析器會為該 Token 創(chuàng)建一個 DOM 節(jié)點,然后將該節(jié)點加入到 DOM 樹中,它的父節(jié)點 就是棧中相鄰的那個元素生成的節(jié)點。
- 如果分詞器解析出來是文本 Token,那么會生成一個文本節(jié)點,然后將該節(jié)點加入到 DOM 樹中,文本 Token 是不需要壓入到棧中,它的父節(jié)點就是當(dāng)前棧頂 Token 所對應(yīng)的 DOM 節(jié)點。
- 如果分詞器解析出來的是EndTag 標(biāo)簽,比如是 EndTag div,HTML 解析器會查看 Token 棧頂?shù)脑厥欠袷?StarTag div,如果是,就將 StartTag div 從棧中彈出,表示該 div 元素解析完成。
樣式計算
樣式計算的目的是為了計算dom節(jié)點中每個元素的具體樣式,具體可以分為以下三個步驟:
-
把css轉(zhuǎn)化為瀏覽器能夠理解的結(jié)構(gòu),可以用document.styleSheet查看
-
轉(zhuǎn)換樣式表中的屬性值,使其標(biāo)準(zhǔn)化
屬性標(biāo)準(zhǔn)化就是將一些屬性值轉(zhuǎn)化為渲染引擎容易理解的,標(biāo)準(zhǔn)化的計算值,比如一些字體的單位是em的就需要轉(zhuǎn)化為px
-
算出dom樹中每個節(jié)點的具體樣式
樣式計算的第一個規(guī)則就是css繼承,第二個是層疊
總之,樣式計算階段的目的是為了計算出DOM節(jié)點中每個元素的具體樣式,在計算過程中需要遵守CSS的繼承和層疊兩個規(guī)則。這個階段最終輸出的內(nèi)容是每個DOM節(jié)點的樣式,并被保存在ComputedStyle的結(jié)構(gòu)內(nèi)。
布局階段
布局也就是計算出dom樹中可見元素的幾何位置,chrome在布局階段需要完成兩個任務(wù):創(chuàng)建布局樹和布局計算
-
創(chuàng)建布局樹
在DOM樹一般還會含有很多不可見的元素,比如head標(biāo)簽,還有使用了
display:none
屬性的元素。所以在顯示之前,我們還要額外地構(gòu)建一棵只包含可見元素布局樹。為了構(gòu)建布局樹,瀏覽器大體上完成了下面這些工作
- 遍歷DOM樹中的所有可見節(jié)點,并把這些節(jié)點加到布局中;
- 而不可見的節(jié)點會被布局樹忽略掉,如
head
標(biāo)簽下面的全部內(nèi)容,再比如body.p.span
這個元素,因為它的屬性包含dispaly:none
,所以這個元素也沒有被包進(jìn)布局樹
-
布局計算
現(xiàn)在我們有了一棵完整的布局樹。那么接下來,就要計算布局樹節(jié)點的坐標(biāo)位置了
分層
接下來,渲染引擎需要為特定的節(jié)點生成專用的圖層,并生成一顆對應(yīng)的圖層樹。圖層疊加起來就是最終的頁面圖像
通常情況下,并不是布局樹的每個節(jié)點都包含一個圖層,如果一個節(jié)點沒有對應(yīng)的層,那么這個節(jié)點就從屬于父節(jié)點的圖層。如上圖中的span標(biāo)簽沒有專屬圖層,那么它們就從屬于它們的父節(jié)點圖層。但不管怎樣,最終每一個節(jié)點都會直接或者間接地從屬于一個層。
滿足以下條件才會被提升為單獨的層
-
第一點,擁有層疊上下文的元素會被提升為單獨的一層
頁面是個二維平面,但是層疊上下文能夠讓HTML元素具有三維概念,這些HTML元素按照自身屬性的優(yōu)先級分布在垂直于這個二維平面的z軸上。你可以結(jié)合下圖來直觀感受下:
-
需要剪裁的地方也會被創(chuàng)建為圖層
標(biāo)簽里面的內(nèi)容超出了標(biāo)簽的寬度和高度,就會出現(xiàn)剪裁。出現(xiàn)這種裁剪情況的時候,渲染引擎會為文字部分單獨創(chuàng)建一個層,如果出現(xiàn)滾動條,滾動條也會被提升為單獨的層
圖層繪制
在完成圖層樹的構(gòu)建之后,渲染引擎會對圖層樹中的每一個圖層進(jìn)行繪制
繪制的過程就是把一個圖層的繪制拆分成很多小的繪制指令,然后再把這些指令按照順序組成一個待繪制列表
繪制列表中的指令其實非常簡單,就是讓其執(zhí)行一個簡單的繪制操作,比如繪制粉色矩形或者黑色的線等。而繪制一個元素通常需要好幾條繪制指令,因為每個元素的背景、前景、邊框都需要單獨的指令去繪制。所以在圖層繪制階段,輸出的內(nèi)容就是這些待繪制列表。
柵格化操作
繪制列表只是用來記錄繪制順序和繪制指令的列表,而實際上繪制操作是由渲染引擎中的合成線程來完成的。
當(dāng)圖層的繪制列表準(zhǔn)備好之后,主線程會把該繪制列表提交(commit)給合成線程
- 通常一個頁面可能很大,但是用戶只能看到其中的一部分,我們把用戶可以看到的這個部分叫做視口(viewport)。
在有些情況下,有的圖層可以很大,比如有的頁面你使用滾動條要滾動好久才能滾動到底部,但是通過視口,用戶只能看到頁面的很小一部分,所以在這種情況下,要繪制出所有圖層內(nèi)容的話,就會產(chǎn)生太大的開銷,而且也沒有必要。
基于這個原因,合成線程會將圖層劃分為圖塊(tile),這些圖塊的大小通常是256x256或者512x512
合成線程會按照視口附近的圖塊來優(yōu)先生成位圖,實際生成位圖的操作是由柵格化來執(zhí)行的。所謂柵格化,是指將圖塊轉(zhuǎn)換為位圖。而圖塊是柵格化執(zhí)行的最小單位。渲染進(jìn)程維護了一個柵格化的線程池,所有的圖塊柵格化都是在線程池內(nèi)執(zhí)行的,運行方式如下圖所示:
通常,柵格化過程都會使用GPU來加速使用,使用GPU生成位圖的過程叫做快速柵格化,或者GPU柵格化,生成的位圖會保存在GPU內(nèi)存中
合成和顯示
一旦所有的圖塊都被柵格化,合成線程就會生成一個繪制圖塊的命令—‘DrawQuad",然后將該命令提交給瀏覽器進(jìn)程
瀏覽器進(jìn)程里面有一個叫viz的組件,用來接收合成線程發(fā)過來的DrawQuad命令,然后根據(jù)DrawQuad命令,將其頁面內(nèi)容繪制到內(nèi)存中,最后再將內(nèi)存顯示在屏幕上。
到這里,經(jīng)過這一系列的階段,編寫好的HTML、CSS、JavaScript等文件,經(jīng)過瀏覽器就會顯示出漂亮的頁面了。
總結(jié)
一個完整的渲染流程大致可總結(jié)為如下
- 渲染進(jìn)程將HTML內(nèi)容轉(zhuǎn)換為能夠讀懂的DOM樹結(jié)構(gòu)。
- 渲染引擎將CSS樣式表轉(zhuǎn)化為瀏覽器可以理解的styleSheets,計算出DOM節(jié)點的樣式。
- 創(chuàng)建布局樹,并計算元素的布局信息。
- 對布局樹進(jìn)行分層,并生成分層樹。
- 為每個圖層生成繪制列表,并將其提交到合成線程。
- 合成線程將圖層分成圖塊,并在光柵化線程池中將圖塊轉(zhuǎn)換成位圖。
- 合成線程發(fā)送繪制圖塊命令DrawQuad給瀏覽器進(jìn)程。
- 瀏覽器進(jìn)程根據(jù)DrawQuad消息生成頁面,并顯示到顯示器上
相關(guān)文章
15 個為編程初學(xué)者準(zhǔn)備的網(wǎng)站(都是國外的一些網(wǎng)站)
今天的文章,我們將分享15個可以學(xué)習(xí)編程的網(wǎng)站,這些網(wǎng)站上提供了很多編程教程,圖書以及編程練習(xí),希望對你有用2024-11-02- 這篇文章主要介紹了web開發(fā)中的長度單位主要包括px,pt,em等,需要的朋友可以參考下2023-08-06
網(wǎng)頁前端開發(fā)的一些尺寸單位(px,rem單位)
px單位是絕對單位,一般用于pc端網(wǎng)頁開發(fā),因為是絕對單位所以在移動端上的使用體驗并不是很好,rem它是描述相對于當(dāng)前根元素字體尺寸,是相對單位,它可以根據(jù)根元素的變換而2023-08-06WEB前端優(yōu)化必備js/css壓縮工具YUI-compressor詳解與集成用法
壓縮工具層次不窮,各有優(yōu)點,選擇適合的壓縮工具為將來做項目開發(fā)使用是一件很重要的事情!!在這介紹YUI-compressor,需要的朋友可以參考下2023-06-21- 瀏覽器是多進(jìn)程的,有瀏覽器主進(jìn)程,網(wǎng)絡(luò)進(jìn)程,渲染進(jìn)程,插件進(jìn)程等,在將html,css,javascript解析成一個頁面的時候,就需要多個進(jìn)程的分工合作2023-05-01
- 本文為大家整理了常用的文件對應(yīng)的MIME類型,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-25
postman中form-data、x-www-form-urlencoded、raw、binary的區(qū)別介紹
這篇文章介紹了postman中form-data、x-www-form-urlencoded、raw、binary的區(qū)別,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-12-28網(wǎng)頁中使用Unicode字符的介紹(&#,\u等)
國際組織制定了可以容納世界上所有文字和符號的字符編碼方案,稱為Unicode,是通用字符集Universal Character Set的縮寫,用以滿足跨語言、跨平臺進(jìn)行文本轉(zhuǎn)換、處理的要求2021-11-27前端實現(xiàn)字符串GBK與GB2312的編解碼(小結(jié))
這篇文章主要介紹了前端實現(xiàn)字符串GBK與GB2312的編解碼(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-12-02- 這篇文章主要介紹了告別硬編碼讓你的前端表格自動計算,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-27