咱们常常写HTML
、CSS
和JavaScript
,写好这些以后,咱们就会在浏览器中看到页面,那浏览器究竟在这背后作了一些什么事情呢?本篇文章将揭晓答案!css
了解浏览器的渲染原理是咱们在通往更深层次的前端开发中不可缺乏的,它可让咱们从更深层次、角度去考虑性能优化等~html
下面进入正文~前端
浏览器会分配一个线程“自上而下,从左到右”依次解析和渲染代码,那么进程和线程是什么,它们之间有着怎样的关系呢?web
一个进程就是一个程序运行的实例。当启动一个程序的时候,操做系统会为该程序建立一块内存,用来存放代码,运行中的数据和一个执行任务的主线程,这样的一个运行环境就叫进程算法
线程不能单独存在,它是由进程来启动和管理的。线程依附于进程,进程中使用多线程并行处理能提高运算效率chrome
一、进程中的任意一线程执行出错,都会致使整个进程的崩溃浏览器
二、线程之间能够共享数据性能优化
三、当一个进程关闭后,操做系统会回收进程所占用的内存bash
四、进程之间的内容相互隔离服务器
了解浏览器的渲染原理,咱们就要从理解HTML
、CSS
和JavaScrip
开始,咱们先来看一张图
HTML
(超文本标记语言),顾名思义,由标记(标签)和文本组成,每一个标签都有本身的语意,浏览器会根据标签和文本展现对应的内容。
CSS
(层叠样式表),由选择器和属性组成,它能够改变HTML
的样式,好比上图中,咱们改变了span
的颜色由蓝色为绿色。
JavaScript
,咱们能够经过JS
完成不少事情,例如上图中修改样式。
下面开始分析渲染的原理
渲染模块因为渲染的机制的复杂,被划分为了不少子阶段,输入的HTML
通过这些子阶段,最后会输出为像素。这样的处理流程就叫作渲染流水线
按照渲染的时间顺序,流水线可分为几个子阶段:构建DOM
树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成
因为浏览器没法直接理解和使用HTML
,因此须要将HTML
转换为浏览器可以理解的结构(DOM
树)
咱们来分析一下下面这段代码会构建出一棵什么样的DOM
树
咱们先将上面的代码运行,而后在浏览器控制台输入document
,看看会有什么效果
咱们一层级一层级的打开就会看到如上图的效果,咱们能够根据这每一层级展开的效果,绘制出一棵DOM
树结构,以下:
接下来,咱们试一下利用JS
修改一下内容,看有什么改变:
咱们能够看到“浏览器”的文字变成了“chrome”
再来看一下DOM
树是否有改变
咱们看到在“浏览器”的位置换成了“chrome”,那么如何让DOM
节点拥有样式?
样式计算,顾名思义,就是计算出DOM
节点中每一个元素的具体样式,这个阶段会分为三部分:
把CSS
转换为浏览器可以理解的结构
转换样式表中的属性值,使其标准化
计算出DOM
树中每一个节点的样式
link
导入外部样式资源浏览器会新开辟一个线程,去服务器获取对应的资源文件(不阻碍主线程的渲染)
style
内嵌样式从上到下解析,解析完继续解析DOM
结构。在真实项目中,若是css
代码不是不少,或是移动端项目,咱们应该使用内嵌式,以此来减小http
资源的请求,提升页面渲染速度
行内样式
@import
导入
它是同步的,不会开辟新线程去加载资源文件,而是让主线程去获取,这阻碍DOM
结构的继续渲染;只有把外部样式导入进来,而且解析后,才会继续渲染DOM
结构
浏览器就像不能理解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;
...
}
复制代码
样式计算有两个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前端日记」,你们能够关注一波~