我们可能都知道浏览器含有一个渲染引擎,用来渲染窗口所展示的内容。默认情况下,渲染引擎可以显示html、xml文档及图片,它也可以借助插件(一种浏览器扩展)显示其他类型数据,例如使用PDF阅读器插件,用于显示PDF格式。这些天研究了一下浏览器的渲染原理,记录渲染引擎最主要的用途——显示应用了CSS之后的html及图片。

一、浏览器的主要功能

  浏览器的主要功能是将用户选择的web资源呈现出来,它需要从服务器请求资源,并将其显示在浏览器窗口中,资源的格式通常是HTML,也包括PDF、image及其他格式。用户用URI(Uniform Resource Identifier统一资源标识符)来指定所请求资源的位置,通过DNS查询,将网址转换为IP地址。大致过程如下: 
  1、输入网址;
  2、浏览器查找域名的IP地址;
  3、浏览器给web服务器发送一个HTTP请求 ;
  4、网站服务的永久重定向响应 ;
  5、浏览器跟踪重定向地址, 并发送另一个获取请求;
  6、服务器“处理”请求,服务器接收到获取请求,然后处理并返回一个响应;
  7、服务器发回一个HTML响应 ;
  8、浏览器开始显示HTML ;
  9、浏览器发送请求,以获取嵌入在HTML中的对象。在浏览器显示HTML时,它会注意到需要获取其他地址内容的标签。这时,浏览器会发送一个获取请求来重新获得这些文件。这些文件就包括CSS/JS/图片等资源,这些资源的地址都要经历一个和HTML读取类似的过程。所以浏览器会在DNS中查找这些域名,发送请求,重定向等等。。。。。。

  那么,一个页面,究竟是如何从我们输入一个网址到最后完整的呈现在我们面前的呢?这就是浏览器渲染要做的工作。

二、浏览器的渲染过程

1、什么是渲染引擎?

网页浏览器的排版引擎也被称为页面渲染引擎,它负责取得网页的内容(HTML、XML、图象等等)、整理信息(例如加入CSS等),以及计算网页的显示方式然后会输出至显示器或打印机。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要排版引擎。

2、渲染主流程

渲染引擎首先通过网络获得所请求文档的内容,通常以8K分块的方式完成。下面是渲染引擎在取得内容之后的基本流程

解析html以构建dom树 -> 构建render树 -> 布局render树 -> 绘制render树

先来看个图:

这里写图片描述

所以,浏览器会解析三个东西: 

(1) HTML/SVG/XHTML,解析这三种文件会产生一个 DOM Tree。 

(2) CSS,解析 CSS 会产生 CSS 规则树。 

(3) JavaScript脚本,主要是通过 DOM API 和 CSSOM API 来操作 DOM Tree 和 CSS Rule Tree.

这里先解释几个重要概念,方便大家理解:  

  • DOM Tree:浏览器将HTML解析成树形的数据结构。  

  • CSS Rule Tree:浏览器将CSS解析成树形的数据结构。  

  • Render Tree(着色树):DOM和CSSOM合并后生成Render Tree。  

  • layout:有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系,从而去计算出每个节点在屏幕中的位置。  

  • painting(绘制):按照算出来的规则,通过显卡,把内容画到屏幕上。

  • reflow(回流/重排):当浏览器发现某个部分发生了点变化影响了布局,需要倒回去重新渲染,内行称这个回退的过程叫 reflow。reflow 会从 <html> 这个 root frame 开始递归往下,依次计算所有的结点几何尺寸和位置。reflow 几乎是无法避免的。现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显 示与隐藏)等,都将引起浏览器的 reflow。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲 染。通常我们都无法预估浏览器到底会 reflow 哪一部分的代码,它们都彼此相互影响着。

  • repaint(重绘):改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸没有变。

注意:(1)display:none 的节点不会被加入Render Tree,而visibility: hidden 则会,所以,如果某个节点最开始是不显示的,设为display:none是更优的。

     (2)display:none 会触发 reflow,而 visibility:hidden 只会触发 repaint,因为没有发现位置变化。

   (3)有些情况下,比如修改了元素的样式,浏览器并不会立刻reflow 或 repaint 一次,而是会把这样的操作积攒一批,然后做一次 reflow,这又叫异步 reflow 或增量异步 reflow。但是在有些情况下,比如resize 窗口,改变了页面默认的字体等,对于这些操作,浏览器会马上进行 reflow。

3、webkit和gecko引擎的渲染过程

  • webkit的主要流程:

 

  • Geoko的主要流程:

  Gecko 里把格式化好的可视元素称做“帧树”(Frame tree)。每个元素就是一个帧(frame)。 webkit 则使用”渲染树”这个术语,渲染树由”渲染对象”组成。webkit 里使用”layout”表示元素的布局,Gecko则称为”reflow”。Webkit使用”Attachment”来连接DOM节点与可视化信息以构建渲染树。一个非语义上的小差别是Gecko在HTML与DOM树之间有一个附加的层 ,称作”content sink”,是创建DOM对象的工厂。

  尽管Webkit与Gecko使用略微不同的术语,这个过程还是基本相同的,如下:

  1)浏览器会将HTML解析成一个DOM树,DOM 树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。

  2)将CSS解析成 CSS Rule Tree 。

  3)根据DOM树和CSSOM来构造 Rendering Tree。注意:Rendering Tree 渲染树并不等同于 DOM 树,因为一些像Header或display:none的东西就没必要放在渲染树中了。

  4)有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。下一步操作称之为layout,顾名思义就是计算出每个节点在屏幕中的位置

  5)再下一步就是绘制即遍历render树,并使用UI后端层绘制每个节点

注意:上述这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。