【極客時間】瀏覽器工作原理與實踐-2 宏觀視角下的瀏覽器 (6講) - 2.5 渲染流程(上):HTML、CSS和JavaScript,是如何變成頁面的?

https://time.geekbang.org/column/article/118205

2.5 渲染流程(上):HTML、CSS和JavaScript,是如何變成頁面的?

2.4講了導航相關的流程,那導航被提交后又會怎么樣呢?

進入了渲染階段

這個階段很重要,了解其相關流程能讓你**“看透”頁面是如何工作的**,有了這些知識,你可以解決一系列相關的問題,比如能熟練使用開發者工具,因為能夠理解開發者工具里面大部分項目的含義能優化頁面卡頓問題,使用 JavaScript 優化動畫流程,通過優化樣式表來防止強制同步布局,等等。

2.5節講渲染流程。通常,編寫好 HTML、CSS、JavaScript 等文件,經過瀏覽器就會顯示出漂亮的頁面(如下圖所示),但是你知道它們是如何轉化成頁面的嗎?

在這里插入圖片描述

從圖中可以看出,左邊輸入的是 HTML、CSS、JavaScript 數據,這些數據經過中間渲染模塊的處理,最終輸出為屏幕上的像素

這中間的渲染模塊就是我們今天要討論的主題。為了能更好地理解下文,可以先結合下圖快速抓住 HTML、CSS 和 JavaScript 的含義:

在這里插入圖片描述

  • HTML 的內容是由標記和文本組成。標記也稱為標簽每個標簽都有它自己的語義,瀏覽器會根據標簽的語義來正確展示 HTML 內容

    比如上面的標簽是告訴瀏覽器在這里的內容需要創建一個新段落,中間的文本就是段落中需要顯示的內容。

  • 如果需要改變 HTML 的字體顏色、大小等信息,就需要用到 CSS。CSS 又稱為層疊樣式表,是由選擇器和屬性組成.

    比如圖中的 p 選擇器,它會把 HTML 里面<p>標簽的內容選擇出來,然后再把選擇器的屬性值應用到<p>標簽內容上。選擇器里面有個 color 屬性,它的值是 red,這是告訴渲染引擎把<p>標簽的內容顯示為紅色。

  • 至于 JavaScript(簡稱為 JS),使用它可以使網頁的內容“動”起來。

    比如上圖中,可以通過 JavaScript 來修改 CSS 樣式值,從而達到修改文本顏色的目的。

搞清楚 HTML、CSS 和 JavaScript 的含義后,那么接下來我們就正式開始分析渲染模塊了。

由于渲染機制過于復雜,所以渲染模塊在執行過程中會被劃分為很多子階段,輸入的 HTML 經過這些子階段,最后輸出像素。我們把這樣的一個處理流程叫做渲染流水線,其大致流程如下圖所示:
在這里插入圖片描述
按照渲染的時間順序,流水線可分為如下幾個子階段:構建 DOM 樹、樣式計算、布局階段、分層、繪制、分塊、光柵化和合成。內容比較多,我會用兩篇文章來為你詳細講解這各個子階段。接下來,在介紹每個階段的過程中,你應該重點關注以下三點內容:

  • 開始每個子階段都有其輸入的內容;
  • 然后每個子階段有其處理過程;
  • 最終每個子階段會生成輸出內容。

理解了這三部分內容,能讓你更加清晰地理解每個子階段。

構建 DOM 樹

為什么要構建 DOM 樹呢?這是因為瀏覽器無法直接理解和使用 HTML,所以需要將 HTML 轉換為瀏覽器能夠理解的結構——DOM 樹

這里我們還需要簡單介紹下什么是樹結構,為了更直觀地理解,你可以參考下面我畫的幾個樹結構:

在這里插入圖片描述

樹這種結構非常像我們現實生活中的“樹”,其中每個點我們稱為節點,相連的節點稱為父子節點。樹結構在瀏覽器中的應用還是比較多的,比如下面我們要介紹的渲染流程,就在頻繁地使用樹結構。

接下來咱們還是言歸正傳,來看看 DOM 樹的構建過程,你可以參考下圖:

在這里插入圖片描述
從圖中可以看出,構建 DOM 樹的輸入內容是一個非常簡單的 HTML 文件,然后經由 HTML 解析器解析,最終輸出樹狀結構的 DOM

為了更加直觀地理解 DOM 樹,你可以打開 Chrome 的“開發者工具”,選擇**“Console”標簽來打開控制臺,然后在控制臺里面輸入“document”后回車**,這樣你就能看到一個完整的 DOM 樹結構,如下圖所示:

在這里插入圖片描述

圖中的 document 就是 DOM 結構,你可以看到,DOM 和 HTML 內容幾乎是一樣的,但是和 HTML 不同的是,DOM 是保存在內存中樹狀結構,可以通過 JavaScript 來查詢或修改其內容

那下面就來看看如何通過 JavaScript 來修改 DOM 的內容,在控制臺中輸入:

document.getElementsByTagName("p")[0].innerText = "black"

這行代碼的作用是把第一個<p>標簽的內容修改為 black,具體執行結果你可以參考下圖:

在這里插入圖片描述

從圖中可以看出,在執行了一段修改第一個<p>標簽的 JavaScript 代碼后,DOM 的第一個 p 節點的內容成功被修改,同時頁面中的內容也被修改了。

好了,現在已經生成 DOM 樹了,但是 DOM 節點的樣式我們依然不知道,要讓 DOM 節點擁有正確的樣式,這就需要樣式計算了

樣式計算(Recalculate Style)

樣式計算的目的是為了計算出 DOM 節點中每個元素的具體樣式,這個階段大體可分為三步來完成。

1. 把 CSS 轉換為瀏覽器能夠理解的結構

那 CSS 樣式的來源主要有哪些呢?你可以先參考下圖:
在這里插入圖片描述
從圖中可以看出,CSS 樣式來源主要有三種:

  • 通過 link 引用的外部 CSS 文件
  • <style>標記內的 CSS
  • 元素的 style 屬性內嵌的 CSS

和 HTML 文件一樣,瀏覽器也是無法直接理解這些純文本的 CSS 樣式,所以當渲染引擎接收到 CSS 文本時,會執行一個轉換操作,將 CSS 文本轉換為瀏覽器可以理解的結構——styleSheets

為了加深理解,你可以在 Chrome 控制臺中查看其結構,只需要在控制臺中輸入 document.styleSheets,然后就看到如下圖所示的結構:

在這里插入圖片描述

從圖中可以看出,這個樣式表包含了很多種樣式,已經把那三種來源的樣式都包含進去了。當然樣式表的具體結構不是我們今天討論的重點,你只需要知道渲染引擎會把獲取到的 CSS 文本全部轉換為 styleSheets 結構中的數據,并且該結構同時具備了查詢和修改功能,這會為后面的樣式操作提供基礎。

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

現在我們已經把現有的 CSS 文本轉化為瀏覽器可以理解的結構了,那么接下來就要對其進行屬性值的標準化操作

要理解什么是屬性值標準化,你可以看下面這樣一段 CSS 文本:

body { font-size: 2em }
p {color:blue;}
span  {display: none}
div {font-weight: bold}
div  p {color:green;}
div {color:red; }

可以看到上面的 CSS 文本中有很多屬性值,如 2em、blue、bold,這些類型數值不容易被渲染引擎理解,所以需要將所有值轉換為渲染引擎容易理解的、標準化的計算值,這個過程就是屬性值標準化

那標準化后的屬性值是什么樣子的?

在這里插入圖片描述

從圖中可以看到,2em 被解析成了 32px,red 被解析成了 rgb(255,0,0),bold 被解析成了 700……

3. 計算出 DOM 樹中每個節點的具體樣式

現在樣式的屬性已被標準化了,接下來就需要計算 DOM 樹中每個節點的樣式屬性了,如何計算呢?

這就涉及到 CSS 的繼承規則和層疊規則了。首先是 CSS 繼承。CSS 繼承就是每個 DOM 節點都包含有父節點的樣式。這么說可能有點抽象,我們可以結合具體例子,看下面這樣一張樣式表是如何應用到 DOM 節點上的。

body { font-size: 20px }
p {color:blue;}
span  {display: none}
div {font-weight: bold;color:red}
div  p {color:green;}

這張樣式表最終應用到 DOM 節點的效果如下圖所示:

在這里插入圖片描述
從圖中可以看出,所有子節點都繼承了父節點樣式。比如 body 節點的 font-size 屬性是 20,那 body 節點下面的所有節點的 font-size 都等于 20。

為了加深你對 CSS 繼承的理解,你可以打開 Chrome 的“開發者工具”,選擇第一個“element”標簽,再選擇“style”子標簽,你會看到如下界面:

在這里插入圖片描述

這個界面展示的信息很豐富,大致可描述為如下。

  • 首先,可以選擇要查看的元素的樣式(位于圖中的區域 2 中),在圖中的第 1 個區域中點擊對應的元素,就可以在下面的區域查看該元素的樣式了

    比如這里我們選擇的元素是<p>標簽,位于 html.body.div. 這個路徑下面。

  • 其次,可以從樣式來源(位于圖中的區域 3 中)中查看樣式的具體來源信息,看看是來源于樣式文件,還是來源于 UserAgent 樣式表

    這里需要特別提下 UserAgent 樣式,它是瀏覽器提供的一組默認樣式,如果你不提供任何樣式,默認使用的就是 UserAgent 樣式。

  • 最后,可以通過區域 2 和區域 3 來查看樣式繼承的具體過程。

以上就是 CSS 繼承的一些特性,樣式計算過程中,會根據 DOM 節點的繼承關系來合理計算節點樣式。

樣式計算過程中的第二個規則是樣式層疊。層疊是 CSS 的一個基本特征,它是一個定義了如何合并來自多個源的屬性值的算法。它在 CSS 處于核心地位,CSS 的全稱“層疊樣式表”正是強調了這一點。

關于層疊的具體規則這里就不做過多介紹了,網上資料也非常多,你可以自行搜索學習。總之,樣式計算階段的目的是為了計算出 DOM 節點中每個元素的具體樣式,在計算過程中需要遵守 CSS 的繼承和層疊兩個規則。這個階段最終輸出的內容是每個 DOM 節點的樣式,并被保存在 ComputedStyle 的結構內。

如果你想了解每個 DOM 元素最終的計算樣式,可以打開 Chrome 的“開發者工具”,選擇第一個“element”標簽,然后再選擇“Computed”子標簽,如下圖所示:

在這里插入圖片描述
上圖紅色方框中顯示了 html.body.div.p 標簽的 ComputedStyle 的值。你想要查看哪個元素,點擊左邊對應的標簽就可以了。

布局階段

現在,我們有 DOM 樹和 DOM 樹中元素的樣式,但這還不足以顯示頁面,因為我們還不知道 DOM 元素的幾何位置信息

那么接下來就需要計算出 DOM 樹中可見元素的幾何位置,我們把這個計算過程叫做布局

Chrome 在布局階段需要完成兩個任務:創建布局樹和布局計算

1 創建布局樹

你可能注意到了 DOM 樹還含有很多不可見的元素,比如 head 標簽,還有使用了 display:none 屬性的元素。所以在顯示之前,我們還要額外地構建一棵只包含可見元素布局樹

我們結合下圖來看看布局樹的構造過程:

在這里插入圖片描述
從上圖可以看出,DOM 樹中所有不可見的節點都沒有包含到布局樹中。

為了構建布局樹,瀏覽器大體上完成了下面這些工作:

  • 遍歷 DOM 樹中的所有可見節點,并把這些節點加到布局樹中;
  • 而不可見的節點會被布局樹忽略掉,

    如 head 標簽下面的全部內容,再比如 body.p.span 這個元素,因為它的屬性包含 dispaly:none,所以這個元素也沒有被包進布局樹。

2. 布局計算

現在我們有了一棵完整的布局樹。那么接下來,就要計算布局樹節點的坐標位置了。布局的計算過程非常復雜,我們這里先跳過不講,等到后面章節中我再做詳細的介紹。

執行布局操作的時候,會把布局運算的結果重新寫回布局樹中,所以布局樹既是輸入內容也是輸出內容,這是布局階段一個不合理的地方,因為在布局階段并沒有清晰地將輸入內容和輸出內容區分開來。針對這個問題,Chrome 團隊正在重構布局代碼,下一代布局系統叫 LayoutNG,試圖更清晰地分離輸入和輸出,從而讓新設計的布局算法更加簡單。

總結

在這里插入圖片描述

在這里插入圖片描述

從圖中可以看出,本節內容我們介紹了渲染流程的前三個階段:DOM 生成、樣式計算和布局。要點可大致總結為如下:

  • 瀏覽器不能直接理解 HTML 數據,所以第一步需要將其轉換為瀏覽器能夠理解的 DOM 樹結構;
  • 生成 DOM 樹后,還需要根據 CSS 樣式表,來計算出 DOM 樹所有節點的樣式;
  • 最后計算 DOM 元素的布局信息,使其都保存在布局樹中

到這里我們的每個節點都擁有了自己的樣式和布局信息,那么后面幾個階段就要利用這些信息去展示頁面了,由于篇幅限制,剩下的這些階段我會在下一篇文章中介紹。

思考時間

最后,給你留個思考題:如果下載 CSS 文件阻塞了,會阻塞 DOM 樹的合成嗎?會阻塞頁面的顯示嗎?

好問題。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/72567.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/72567.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/72567.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

小模型和小數據可以實現AGI嗎

小模型和小數據很難實現真正的 通用人工智能&#xff08;AGI, Artificial General Intelligence&#xff09;&#xff0c;但在特定任務或受限環境下&#xff0c;可以通過高效的算法和優化方法實現“近似 AGI” 的能力。 1. 為什么小模型小數據難以實現 AGI&#xff1f; AGI 需…

Android14 OTA差分包升級報kPayloadTimestampError (51)

由于VF 架構&#xff0c; 所以鏡像的打包時間可能存在偏差&#xff0c; 如 boot.img 和 客制化的一些鏡像打包 可能會在 vendor 側進行打包。 而 與system 側進行merge 時&#xff0c;時間戳比較亂&#xff0c;為了解決這個問題&#xff0c;讓時間戳進行統一。 使用adb方式驗證…

CMake學習筆記(一):工程的新建和如何將源文件生成二進制文件

cmake是我們在工作過程中比較常見的一個工具&#xff0c;該系列文章是自己用來學習的筆記。目前只是記錄下自己學習cmake的過程中的一些重要的知識點&#xff0c;其是以項目需求為導向并非完整的cmake的學習路線和系統&#xff0c;同樣也并非適合所有的人。 1.生成一個可執行文…

重定位(1)

一、重定位 1、對于有強大ROM的板子&#xff0c;他們會將上電后的程序放到指定RAM內存 2、無強大片內ROM的板子&#xff0c;自己編程序讓他知道RAM內存指定位置 指定位置&#xff1a;就是鏈接地址&#xff0c;指定哪里&#xff0c;哪里就被編譯好一塊內存用來存放上電的程序 …

自由學習記錄(41)

代理服務器的核心功能是在客戶端&#xff08;用戶設備&#xff09;和目標服務器&#xff08;網站/資源服務器&#xff09;之間充當“中介”&#xff0c;具體過程如下&#xff1a; 代理服務器的工作流程 當客戶端希望訪問某個網站&#xff08;比如 example.com&#xff09;時&…

Jadx Gui 的詳細介紹、安裝指南、使用方法及配置說明

Jadx Gui&#xff1a;安卓應用逆向分析神器 一、Jadx Gui 簡介 Jadx 是一款開源的 Android 反編譯工具&#xff0c;支持將 .apk、.aab、.dex 等文件反編譯為可讀的 Java/Kotlin 源代碼和資源文件&#xff08;如 XML、PNG&#xff09;。其特點包括&#xff1a; 圖形化界面&am…

Linux+apache之 瀏覽器訪問云服務器磁盤的圖片,通過tomcat

https://javab.blog.csdn.net/article/details/80580520 安裝tomcact 修改添加 <Context docBase"/home/wyp/images" path"/img" debug"0" reloadable"true" />修改完成后保存重啟tomcat服務。 測試訪問方式&#xff1a;http…

軟件工程與實踐(第4版 新形態) 練習與實踐1

軟件工程與實踐&#xff08;第4版 新形態&#xff09; 練習與實踐1 1.填空題 (1)程序&#xff0c;文檔 (2)系統軟件&#xff0c;支撐軟件&#xff0c;應用軟件 (3)系統方法 (4)軟件開發和維護 (5)工程的概念、原理、技術和方法 (6)實現軟件的優質高產 (7)軟件開發技術和…

基于遺傳算法的無人機三維路徑規劃仿真步驟詳解

基于遺傳算法的無人機三維路徑規劃仿真步驟詳解 一、問題定義 目標:在三維空間內,尋找從起點到終點的最優路徑,需滿足: 避障:避開所有障礙物。路徑最短:總飛行距離盡可能短。平滑性:轉折角度不宜過大,降低機動能耗。輸入: 三維地圖(含障礙物,如立方體、圓柱體)。起…

LIUNX學習-線程

線程概念 一個進程需要訪的大部分資源&#xff0c;諸如自身的代碼、數據、new\malloc的空間數據、命令行參數和環境變量、動態庫、甚至是系統調用訪問內核代碼…都是通過虛擬地址空間來訪問的。換而言之&#xff0c;進程地址空間是進程的資源窗口&#xff01;&#xff01; ? …

1.Big-endian/ little endian大端對齊、小端對齊

一、大端模式、小端模式的介紹 Little endian&#xff1a;是低位字節排放在內存的低地址端、高位字節排放在內存的高地址端。 Big-endian&#xff1a;是高位字節排放在內存的低地址端、低位字節排放在內存的高地址端。 西門子是大端模式&#xff0c;因為比如 MW100 MB100(高位…

[mybatis]resultMap詳解

resultMap Mybatis中提供了resultMap功能&#xff0c;可以將數據庫查詢結果映射到Java對象&#xff0c;用于解決 字段名與屬性名不一致 或 復雜關系&#xff08;如一對多&#xff09;的映射問題。 比如一個User類&#xff0c;在它的屬性里還有另一個子對象&#xff08;或者多…

SpringBoot Actuator

SpringBoot Actuator 一、簡介二、入門1、依賴2、默認監控指標3、查詢監控指標4、全量監控指標 三、Spring Boot Admin1、主要功能2、Admin3、Client4、應用墻5、其他 四、定制化1、定制Health端點2、定制Info端點3、定制Metrics端點4、定制Endpoint端點 一、簡介 SpringBoot自…

python標識符

在 Python 中&#xff0c;標識符&#xff08;Identifier&#xff09;是指用來標識變量、函數、類、模塊等的名稱。標識符的命名規則如下&#xff1a; 1. 標識符的命名規則 字母、數字和下劃線&#xff1a;標識符可以由字母&#xff08;a-z, A-Z&#xff09;、數字&#xff08;…

06 HarmonyOS Next性能優化之LazyForEach 列表渲染基礎與實現詳解 (一)

溫馨提示&#xff1a;本篇博客的詳細代碼已發布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下載運行哦&#xff01; 目錄 一、代碼結構概覽二、詳細代碼解析1. 數據源管理實現2. 數據結構定義3. 優化的列表項組件4. 主列表組件實現 一、代碼結構概覽 本文將詳細解…

vscode 查看3d

目錄 1. vscode-3d-preview obj查看ok 2. vscode-obj-viewer 沒找到這個插件&#xff1a; 3. 3D Viewer for Vscode 查看obj失敗 1. vscode-3d-preview obj查看ok 可以查看obj 顯示過程&#xff1a;開始是綠屏&#xff0c;過了1到2秒&#xff0c;后來就正常看了。 2. vsc…

excel 斜向拆分單元格

右鍵-合并單元格 右鍵-設置單元格格式-邊框 在設置好分割線后&#xff0c;你可以開始輸入文字。 需要注意的是&#xff0c;文字并不會自動分成上下兩行。 為了達到你期望的效果&#xff0c;你可以通過 同過左對齊、上對齊 空格鍵或使用【AltEnter】組合鍵來調整單元格中內容的…

家政保潔維修行業有沒有必要做小程序?

【家政創業必看】家政行業小程序值得做嗎&#xff1f;4大核心優勢告訴你&#xff01; 隨時隨地下單&#xff1a;客戶手機一鍵預約&#xff0c;告別找電話/翻頁面的麻煩 品牌專業升級&#xff1a;精美界面服務詳情用戶評價&#xff0c;打造可信賴形象 營銷神器&#xff1…

利用Python爬蟲按圖搜索1688商品(拍立淘)

在電商領域&#xff0c;按圖搜索商品&#xff08;拍立淘&#xff09;已成為一種重要的功能&#xff0c;尤其適合用戶通過圖片快速查找相似商品。1688開放平臺提供了按圖搜索商品的API接口&#xff0c;允許開發者通過圖片獲取相關的商品信息。本文將詳細介紹如何使用Python爬蟲技…

20250305隨筆 HTML2Canvas 詳解與使用指南

1. 簡介 html2canvas 是一個用于將 HTML 頁面或特定 DOM 元素轉換為 Canvas 畫布的 JavaScript 庫。它通過解析 HTML 和 CSS&#xff0c;生成等效的 Canvas 圖像&#xff0c;從而實現網頁截圖功能。 2. 安裝 可以使用 npm 或 yarn 安裝 html2canvas&#xff0c;也可以通過 C…