【瀏覽器】HTML、CSS和JS如何變成頁面的?

寫在前面

咱們常常寫HTMLCSSJavaScript,寫好這些以後,咱們就會在瀏覽器中看到頁面,那瀏覽器究竟在這背後作了一些什麼事情呢?本篇文章將揭曉答案!css

瞭解瀏覽器的渲染原理是咱們在通往更深層次的前端開發中不可缺乏的,它可讓咱們從更深層次、角度去考慮性能優化等~html

下面進入正文~前端

進程、線程

瀏覽器會分配一個線程「自上而下,從左到右」依次解析和渲染代碼,那麼進程和線程是什麼,它們之間有着怎樣的關係呢?web

進程

一個進程就是一個程序運行的實例。當啓動一個程序的時候,操做系統會爲該程序建立一塊內存,用來存放代碼,運行中的數據和一個執行任務的主線程,這樣的一個運行環境就叫進程算法

線程

線程不能單獨存在,它是由進程來啓動和管理的。線程依附於進程,進程中使用多線程並行處理能提高運算效率chrome

二者之間的關係

一、進程中的任意一線程執行出錯,都會致使整個進程的崩潰瀏覽器

二、線程之間能夠共享數據性能優化

三、當一個進程關閉後,操做系統會回收進程所佔用的內存bash

四、進程之間的內容相互隔離服務器

渲染機制

從HTML、CSS和JavaScript開始

瞭解瀏覽器的渲染原理,咱們就要從理解HTMLCSSJavaScrip開始,咱們先來看一張圖

HTML(超文本標記語言),顧名思義,由標記(標籤)和文本組成,每一個標籤都有本身的語意,瀏覽器會根據標籤和文本展現對應的內容。

CSS(層疊樣式表),由選擇器和屬性組成,它能夠改變HTML的樣式,好比上圖中,咱們改變了span的顏色由藍色爲綠色。

JavaScript,咱們能夠經過JS完成不少事情,例如上圖中修改樣式。

下面開始分析渲染的原理

渲染流水線

渲染模塊因爲渲染的機制的複雜,被劃分爲了不少子階段,輸入的HTML通過這些子階段,最後會輸出爲像素。這樣的處理流程就叫作渲染流水線

按照渲染的時間順序,流水線可分爲幾個子階段:構建DOM樹、樣式計算、佈局階段、分層、繪製、分塊、光柵化和合成

構建DOM樹

因爲瀏覽器沒法直接理解和使用HTML,因此須要將HTML轉換爲瀏覽器可以理解的結構(DOM樹)

樹結構示意圖

DOM樹的構建過程

咱們來分析一下下面這段代碼會構建出一棵什麼樣的DOM

咱們先將上面的代碼運行,而後在瀏覽器控制檯輸入document,看看會有什麼效果

咱們一層級一層級的打開就會看到如上圖的效果,咱們能夠根據這每一層級展開的效果,繪製出一棵DOM樹結構,以下:

接下來,咱們試一下利用JS修改一下內容,看有什麼改變:

咱們能夠看到「瀏覽器」的文字變成了「chrome」

再來看一下DOM樹是否有改變

咱們看到在「瀏覽器」的位置換成了「chrome」,那麼如何讓DOM節點擁有樣式?

樣式計算

樣式計算,顧名思義,就是計算出DOM節點中每一個元素的具體樣式,這個階段會分爲三部分:

  • CSS轉換爲瀏覽器可以理解的結構

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

  • 計算出DOM樹中每一個節點的樣式

CSS樣式來源

  • link導入外部樣式資源

瀏覽器會新開闢一個線程,去服務器獲取對應的資源文件(不阻礙主線程的渲染)

  • style內嵌樣式

從上到下解析,解析完繼續解析DOM結構。在真實項目中,若是css代碼不是不少,或是移動端項目,咱們應該使用內嵌式,以此來減小http資源的請求,提升頁面渲染速度

  • 行內樣式

  • @import導入

它是同步的,不會開闢新線程去加載資源文件,而是讓主線程去獲取,這阻礙DOM結構的繼續渲染;只有把外部樣式導入進來,而且解析後,纔會繼續渲染DOM結構

把CSS轉換爲瀏覽器可以理解的結構

瀏覽器就像不能理解HTML同樣,不理解CSS,因此當渲染引擎接收到CSS文件時,會執行轉換操做,將CSS文本轉換爲瀏覽器能夠理解的styleSheets結構。

HTML中,在瀏覽器中輸入document能夠查看html的結構。在css中,能夠輸入document.styleSheets看到css的結構

如今的結構是空的,咱們來加一些樣式,看看效果

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

屬性值標準化就是將全部值轉換爲渲染引擎容易理解的、標準化的計算值。咱們大體看一下效果:

  • 標準化前
body {
    font-size: 2em;
    color: black;
    font-weight: bold;
    ...
}
複製代碼
  • 標準化後
body {
    font-size: 16px;
    color: rgb(0, 0, 0);
    font-weight: 700;
    ...
}
複製代碼

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

樣式計算有兩個CSS的規則:繼承規則和層疊規則

  • CSS繼承規則

CSS繼承就是每一個DOM節點都包含有父節點的樣式。咱們來看一下下面這段代碼中如何應用到DOM節點上

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        h1 {
            color: red;
        }

        div {
            color: blue;
        }

        span {
            font-size: 16px;
        }
    </style>
</head>
<body>
    <h1>掘金</h1>
    <div>
        <span>瀏覽器</span>
        <span>渲染原理</span>
        構建DOM樹
    </div>
</body>
</html>
複製代碼

子節點會擁有父節點的樣式,由此咱們能夠畫出這樣一張圖

咱們還能夠打開控制檯,看一下選中span標籤,都會看到哪些內容

經過上圖,咱們可看到一個元素的樣式、繼承過程等,userAgent樣式是瀏覽器默認的內置樣式,若是咱們不提供任何樣式,就會使用此樣式。

  • 樣式層疊規則

層疊在CSS處於核心地位,它是CSS的一個基本特徵,它定義瞭如何合併來自多個源的屬性值的算法。

樣式計算階段最終輸出的內容是每一個DOM節點的樣式,而且保存在了ComputedStyle中。咱們能夠經過控制檯看到某個DOM元素最終的計算樣式

佈局階段

如今咱們不知道DOM元素的幾何位置信息,因此如今咱們須要計算出DOM樹中可見元素的幾何位置,這個計算過程就叫作佈局。佈局階段有兩個過程:

  • 建立佈局樹

  • 佈局計算

建立佈局樹

建立佈局樹的意思就是建立一棵只包含可見元素的樹。咱們來看下面一段代碼建立佈局樹的過程

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        h1 {
            color: red;
        }

        div {
            color: blue;
        }

        div span {
            font-size: 16px;
        }

        div span:last-child {
            display: none;
        }
    </style>
</head>
<body>
    <h1>掘金</h1>
    <div>
        <span>瀏覽器</span>
        <span>渲染原理</span>
        構建DOM樹
    </div>
</body>
</html>
複製代碼

構建佈局樹的過程當中,DOM樹中全部不可見的節點都不會包含在這棵樹中。瀏覽器會遍歷DOM樹中全部能看見的節點,而後把這些節點加入到佈局中;不可見的節點就會被忽略,head標籤下面的內容、div下最後一個span節點都不會在佈局樹中,咱們看一下這個過程圖感覺一下~

佈局計算

佈局計算就是計算佈局樹節點的座標位置。這個計算過程極爲複雜。

分層

渲染引擎會爲特定的節點生成專用的圖層,並生成一棵對應的圖層樹。這樣作是由於頁面中可能含有不少複雜的效果,咱們能夠打開控制檯看一下頁面的分層狀況

咱們能夠看到,渲染引擎給頁面分了不少圖層,這些圖層會按照必定順序疊加在一塊兒,造成最終的頁面

那麼圖層的來源有哪些?

一、擁有層疊上下文屬性的元素會被提高爲單獨的一層

層疊上下文可使可以使HTML元素具備三維的概念,這些HTML元素按照自身屬性的優先級分佈在垂直於這個二維平面的z軸上。哪些元素具備層疊上下文屬性?

二、須要剪裁的地方會被建立爲圖層

當咱們建立一個有寬度和高度的div時,裏面的文字內容可能會超出這個區域,這時候渲染引擎會把裁剪文字內容的一部分用於顯示在div區域,例如

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 100px;
            height: 100px;
            background: yellow;
            overflow: auto;
        }
    </style>
</head>
<body>
    <div>
        咱們常常寫`HTML`、`CSS`和`JavaScript`,寫好這些以後,咱們就會在瀏覽器中看到頁面,那瀏覽器究竟在這背後作了一些什麼事情呢?本篇文章將揭曉答案!

        瞭解瀏覽器的渲染原理是咱們在通往更深層次的前端開發中不可缺乏的,它可讓咱們從更深層次、角度去考慮性能優化等~
    </div>
</body>
</html>
複製代碼

運行結果

咱們再打開控制檯的layers看一下效果

能夠看到渲染引擎爲文字部分單首創建了一個圖層。

在佈局樹中的節點若是擁有對應的圖層,這個節點就是一個圖層,若是沒有,這個節點就屬於父節點的圖層,以下圖:

圖層繪製

建立好圖層樹後,渲染引擎會繪製圖層樹中的每一個圖層。渲染引擎會將圖層繪製分解爲不少小的繪製指令,而後將這些指令按照順序組成待繪製列表,咱們能夠打開控制檯的layers,選擇document層,看一下效果

柵格化操做

柵格化就是將圖塊轉換位位圖,圖塊是柵格化執行的最小單位。渲染進程維護了一個柵格化的線程池,全部圖塊的柵格化都是在線程池內執行的。

圖層繪製列表準備好以後,主線程會把這個繪製列表提交給合成線程,繪製操做由渲染引擎中的合成線程來完成。

合成線程將圖層劃分爲圖塊,而後合成線程會按照視口(可見區域)附近的圖塊優先生成位圖。

合成與顯示

全部的圖塊都被光柵化後,合成線程會生成一個繪製圖塊的命令(DrawQuad),而後將該命令提交給瀏覽器進程。瀏覽器進程裏面viz組件用來接收DrawQuad命令,將其頁面內容繪製到內存中,最後將內存顯示到屏幕。這個時候,咱們就看到了頁面

完善渲染流水線示意圖

根據上文中描述,咱們能夠畫出這樣一張圖

我還在網上找到了另一張圖

這兩張圖都是描述瀏覽器的渲染流程的。

寫在最後

本篇文章參考了極客時間中《瀏覽器工做原理與實踐》一文

本文總結了瀏覽器是如何讓咱們看到頁面的原理,若有不對之處還請你們指出,咱們共同窗習,共同進步~以爲文章對你有幫助,能夠給點個贊呦~

最後,分享一下個人我的微信公衆號「web前端日記」,你們能夠關注一波~

相關文章
相關標籤/搜索