程序员:HTML、CSS、JavaScript是如何变成页面的?

开发 前端
从输入HTML、CSS、JavaScript到浏览器渲染出我们预期的效果,渲染流程分为这几个子阶段:构建DOM树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。

从输入HTML、CSS、JavaScript到浏览器渲染出我们预期的效果,渲染流程分为这几个子阶段:构建DOM树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。

以下面这段html举例讲解这几个过程: 

  1. //aa.html  
  2. <!DOCTYPE html>  
  3. <html lang="en">  
  4. <head>  
  5. <meta charset="UTF-8">  
  6. <title>Title</title>  
  7. <link rel="stylesheet" href="./aa.css">  
  8. </head>  
  9. <body>  
  10. <p id="p-one" style="color:red">hello</p>  
  11. <p id="p-two">hi</p>  
  12. <button id="p-three">ok</button>  
  13. </body>  
  14. <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>  
  15. <script src="./aa.js"></script>  
  16. </html>  
  1. //aa.css  
  2. #p-two {  
  3. font-size:2rem;  
  4.  
  1. //aa.js  
  2. $("#p-three").bind("click", function() {  
  3. $("#p-three").css("color", "blue");  
  4. }); 

构建DOM树

因为浏览器⽆法直接理解和使⽤HTML,所以需要将HTML转换为浏览器能够理解的结构——DOM树。

样式计算

样式计算的⽬的是为了计算出DOM节点中每个元素的具体样式,分为三个步骤:

1. 把CSS转换为浏览器能够理解的结构—styleSheets

2.  转换样式表中的属性值,使其标准化,如: 

  1. font-size:2em->font-size:32px  
  2. p{color:blue}->p{color:rgb(0,0,255)}  
  3. div{font-weight:bold}->div{font-weight:700} 

3.计算出DOM树中每个节点的具体样式,最终输出的内容是每个DOM节点的样式,并被保存在ComputedStyle的结构内。

布局阶段

现在,以及有了DOM树和DOM树中元素的样式,但还不足以显示页面,因为还不知道DOM元素的几何位置信息,布局阶段就是需要计算出DOM树中元素的几何位置,包括以下几个步骤:

创建布局树

DOM树中包含很多不可见的标签,比如某个标签使用了属性"display:none"。所以在显示之前,还要额外地构建一棵只包含可见元素的布局树,浏览器创建布局树的大致流程为:遍历DOM树中所有可见节点,并加入布局树中,忽略不可见节点。

布局计算

计算每个元素的几何坐标位置,并将这些信息保存在布局树中。

小结前三个阶段:在HTML页面内容被提交给浏览器渲染引擎后,渲染引擎首先将HTML解析为浏览器可以理解的DOM;然后根据CSS样式表,计算出DOM数所有节点的样式;接着又计算每个元素的几何坐标位置,并将这些信息保存在布局树中。

分层

有了每个元素的样式和位置信息,但还是不能开始着手绘制页面,因为页面中还有很多复杂的效果,如3D变化、页面滚动等,为了实现这些效果,渲染引擎还需要为特定节点生成专门的图层,并生成一颗对应的图层树,即有些元素实际上是被分成了很多层,这些图层叠加后合成了最终的页面。只要满足下面两个条件之一的元素就会可以生成一个对应的图层:

拥有层叠上下文属性的元素会被提升为单独的一层

从图中可以看出,明确定位属性的元素、定义透明属性的元素、使用CSS滤镜的元素等,都拥有层叠上下文属性。

需要裁减的地方也会被创建为图层

举例:在css中指定了一个div大width和height属性后,如果div子元素p标签的文字内容超过了widthheight大小,就会只把能在widthheight面积内能显示的内容显示出来,其他内容被裁减掉了。

图层绘制

有了图层树之后,渲染引擎会对图层树中的每个图层进行绘制。图层绘制阶段,就是输入各种绘制指令组成的列表(注意,这个阶段还不是真正地着手绘制)。

在原aa.html文件中添加代码<div style="width:300px;height:300px;background: green;">pp</div>下图中,红色区域就是绘制列表,粉色区域显示的是绘制过程,可点击任何一个绘制过程查看。

分块和栅格化操作

绘制列表只是用来记录绘制顺序和绘制指令,而实际绘制操作是由渲染引擎中的合成线程来完成的。当图层的绘制列表准备好之后,主线程就会把绘制列表提交给合成线程。合成线程会将图层划分为图块,视口(就是当前窗口可见的区域)附近的图块优先生产位图,生产位图的操作实际由栅格化来执行(栅格化的具体含义可自行百度)。渲染进维护了一个栅格化线程池,所有的图块栅格化都是在线程池内执行的,该过程会使用GPU来加速,生产的位图被保存在GPU内存中。

合成和显示

当所有图块都被光栅化(栅格化)后,合成线程就会生成绘制图块的命令,然后该命令提交给浏览器进程(这里简单说下Chrome浏览器多进程架构,其将浏览器分为:渲染进程、插件进程、GPU进程和浏览器主进程,浏览器主进程包含UI模块、网络模块、文件模块等),浏览器进程将其页面内容绘制到内存中,最后再将内存内容显示在屏幕上。

至此,HTML+CSS+JavaScript就能生成我们所看见的页面了。

总结

一个完整的渲染流程大致如下:

  •  渲染进程将HTML内存转换为浏览器能够识别的DOM数据结构
  •  渲染引擎将CSS样式表转换为浏览器能够识别的sytleSheets,计算出DOM节点的样式
  •  创建布局树,包括可见元素以及元素的位置计算
  •  渲染引擎为达到分层条件的节点生成对应的图层,所有图层组合成一颗图层树
  •  生成图层的绘制列表,记录绘制顺序和绘制指令
  •  有合成线程进行栅格化操作,将图层划分为图块,渲染进程把生成的图块发送给GPU,在GPU中执行生成图块的位图
  •  所有图块被栅格化之后,合成线程会发送绘制图块的命令给浏览器进程,在浏览器进程中进行图块合成并最红显示到屏幕上 

 

责任编辑:庞桂玉 来源: 今日头条
相关推荐

2020-04-21 14:00:25

HTMLCSSJS

2013-04-26 13:50:46

程序员

2015-02-03 02:40:33

程序员盲人程序员

2013-11-04 09:39:16

程序员信仰

2020-12-07 11:29:24

ReactVueVue3

2010-03-02 10:13:56

程序员面试

2015-04-10 19:37:34

程序员

2012-07-20 11:16:26

程序员

2012-02-01 09:30:54

HTML 5

2021-02-20 13:55:35

程序员计算机技术

2009-07-16 09:12:16

程序员偷懒技巧

2015-11-17 09:30:23

程序员招聘建议

2015-06-25 09:32:55

JavaScript程序员

2015-06-25 09:53:13

JavaScript程序员

2015-06-25 19:23:03

JavaScript程序员

2018-05-15 10:34:50

JavaScript语言互联网

2013-04-17 10:28:40

程序员

2013-07-24 14:17:10

2013-04-22 09:05:11

程序员

2016-04-28 11:17:33

互动出版网
点赞
收藏

51CTO技术栈公众号