浏览器结构
浏览器主要组件有 7 个,用户界面,浏览器引擎,渲染引擎,网络,用户界面 后端,JS 解析器,数据存储
- 用户界面: 除了浏览器主窗口显示请求的页面外,其他显示的各部分都属于用户界面,如地址栏,状态栏,工具栏等
- 浏览器引擎:在用户界面和渲染引擎之间传送指令
- 渲染引擎: 负责显示所请求的内容。解析 HTML 和 CSS,并将解析后的内容显示在屏幕
- 网络:用于网络调用,例如 HTTP 请求
- JS 解析器:用于解析和执行 JavaScript 代码
- 数据存储:持久层,浏览器需要在硬盘保持各种数据,例如 Cookie。浏览器还支持存储机制,如
LocalStorage
,IndexedDB
,WebSQL
渲染引擎(Rendering engine)
不同浏览器使用不同的渲染引擎
- Blink: Chrome, Opera
- Webkit: Safari
- Gecko: Firefox
- Trident: Internet Explorer
- EdgeHTML: Edge
- Presto: Opera(遗留)
渲染流程
渲染引擎一开始会从网络层获取请求文档的内容,内容大小一般限制在 8kb 的块以内。
然后进行如下基本流程:
- 解析 HTML 文档,并将元素转为内容树(content tree)中的 DOM 节点;
- 解析 css 样式,样式消息和 HTML 中的可视化指令一起创建了渲染树(redner tree)
- 渲染树包含带有颜色和尺寸等视觉属性的矩形,这些矩形会按其排列的顺序在屏幕上显示
- 渲染树构建完成之后,进入布局阶段,也就是为每一个节点分配一个它应该出现在屏幕上的确切坐标
- 绘制阶段,渲染引擎会遍历渲染树,并由用户界面后端层将每个节点绘制处理
注意: 这是一个渐进的过程。为了获得更好的用户体验,渲染引擎将会尽快在屏幕显示内容。它不会等到所有 HTML 都被解析后才开始构建渲染树、设置布局。在不断接受和处理来自网络的其余内容的同时,渲染引擎会将部分内容解析并显示。
解析/DOM 树构建
树包含 DOM 节点,指的是树是由实现了某个 DOM 接口的元素构成的
解析
解析文档是指将文档转化成为有意义的,可以让代码理解、使用的结构。解析得到的结构通常代表了文档结构的节点树,它被称之为解析树/语法树。
- HTML 解析:将 HTML 标记解析成解析树。解析树是由 DOM 元素和属性节点构成的树结构。DOM(文档对象模型),是 HTML 文档的对象表示,同时也是外部内容与 HTML 元素之间的接口
- CSS 解析: 将 CSS 文件解析成 StyleSheet 对象,且每个对象都包含 CSS 规则。CSS 规则对象则包含选择器和声明对象。
脚本顺序
解析器遇到<script>
标记时立即解析并执行脚本,文档的解析将停止,直到脚本执行完毕。如果脚本是外部的,解析过程会停止,直到从网络同步获取资源完成后再执行。脚本标注为defer
,它不会停止文档解析,而是等到解析结束才执行;脚本标注为async
,它表示异步,由其它线程解析和执行,文档解析不受影响
渲染树构建
在 DOM 树构建的同时,浏览器还会构建另一个树结构,渲染树,它是由可视化元素按照其显示顺序而组成的树,即文档的可视化表示。其目的是使让内容按照正确的顺序绘制。
webkit 将渲染树中的元素成为渲染对象/渲染器,它知道如何布局并将自身及其子元素绘制出来。RenderObject 类使所有渲染对象的基类,其定义如下:
1 | calss RenderObject { |
- 每个渲染对象都代表一个矩形区域,通常对应于相关节点的 CSS 框
渲染树和 DOM 树的关系
- 渲染对象和 DOM 元素相对应,但并非一一对应,非可视化的 DOM 元素不会插入 DOM 树,如
<head>
元素,如果元素的样式display:none;
,该元素也不在渲染树中。但visibility:hidden;
的元素仍会显示。 - 有些 DOM 元素对应多个可视化对象,它们往往具有复杂结构的元素,无法用单一的矩形来描述。例如,
<select>
元素有 3 个渲染对象,显示区域,下拉列表框,按钮。 - 有些渲染对象对应于 DOM 节点,但在树中的位置与 DOM 节点不同。浮动定位,绝对定位的元素,处于正常的流程之外,放置在树中的其他地方,而放置在原位的使占位对象
构建渲染树的流程
处理<html>
,<body>
标记会构建渲染树的根节点。这个根节点渲染对象对应于 CSS 最上层的容器 block,且包含了其他所有的 block。它的尺寸就是视口,即浏览器窗口显示区域的尺寸。渲染树的其余部分以 DOM 树节点插入的形式来构建。
- 构建渲染树时,需要计算每一个渲染对象的可视化属性,这是通过计算每个元素的样式属性来完成的,
布局
渲染对象在创建完成并添加到渲染树时,并不包含位置和大小信息。计算这些值的过程称为布局或重排。
Dirty 位系统
为了避免对所有细小的更改都进行整体布局,浏览器采用了一种弄”dirty 位”的系统。如果某个渲染对象发生了更改,或将自身或其子代标记为”dirty”,表示需要进行布局
全局布局和增量布局
- 全局布局(往往是同步触发的)指触发了整个渲染树范围的布局,触发原因可能包括:
- 影响所有渲染对象的全局更改,如字体大小
- 屏幕大小调整
- 当渲染对象为 dirty 时,会异步触发增量布局。浏览器会将“reflow 命令”加入队列,而调度程序 会触发这些命令的批量执行。
- 请求样式信息的脚本可同步触发增量布局
绘制
在绘制阶段,系统会遍历渲染树,并调用渲染对象的”paint”方法,将渲染对象绘制在屏幕上。绘制工作用户界面基础组件完成的。
绘制顺序
CSS2 规范定义了绘制流程的顺序,即按照属性z-index
来决定绘制顺序
- 根元素具有根层叠上下文
- z-index 不为”auto”的定位元素,就创建了一个新的层叠上下文(Stacking Context)
- 定位元素以及父元素为 flex 定位的元素,必须依赖 z-index 值才能创建层叠上下位,所以统称为依赖 z-index 的层叠上下文元素。而其他属性即不依赖 z-index 的层叠上下文。
- 一个层叠上下文有 7 中层叠等级,由低到高:
- 背景和边框: 层叠上下文的元素的背景和边框
- 负 z-index 值:层叠上下文内负 z-index 值的子元素
- 块级盒: 文档流中非行内非定位的子元素
- 浮动盒: 非定位的浮动元素
- 行内盒:文档流中行内非定位子元素
- z-index:0
- 正 z-index 的值
- 正 z-index 的值