【浏览器】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前端日记」,你们能够关注一波~

相关文章
相关标签/搜索