浏览器首先使用 HTTP 协议或者 HTTPS 协议,向服务端请求页面
HTTP 协议是基于 TCP 协议出现的,对 TCP 协议来说,TCP 协议是一条双向的通讯通道,HTTP 在 TCP 的基础上,规定了 Request-Response 的模式。这个模式决定了通讯必定是由浏览器端首先发起的。
大部分情况下,浏览器的实现者只需要用一个 TCP 库,甚至一个现成的 HTTP 库就可以搞定浏览器的网络通讯部分。HTTP 是纯粹的文本协议,它是规定了使用 TCP 协议来传输文本格式的一个应用层协议。
把请求回来的 HTML 代码经过解析,构建成 DOM 树
这里需要先了解状态机
用状态机做词法分析,其实正是把每个词的“特征字符”逐个拆开成独立状态,然后再把所有词的特征字符链合并起来,形成一个联通图结构。
在 C/C++ 和 JavaScript 中,实现状态机的方式大同小异:我们把每个函数当做一个状态,参数是接受的字符,返回值是下一个状态函数。
在接收的同时,即开始构建 DOM 树,由构建 DOM 树的算法去实现。简单说就是遇到不同得节点输出不同的类型,从父到子,从先到后,一个一个节点构造,并且挂载到 DOM 树上的。
计算 DOM 树上的 CSS 属性
把 CSS 规则做一下处理,需要先经过词法分析和语法分析,变成计算机能够理解的结构。在上一步中,依次拿到上一步构造好的元素,去检查它匹配到了哪些规则,再根据规则的优先级,做覆盖和调整。
而 CSS 选择器中有如下几种,把 CSS 规则应用到 DOM 树上,为 DOM 结构添加显示相关属性。
空格: 后代,选中它的子节点和所有子节点的后代节点。
>: 子代,选中它的子节点。
+:直接后继选择器,选中它的下一个相邻节点。
~:后继,选中它之后所有的相邻节点。
||:列,选中表格中的一列。
接下来就是排版。浏览器最基本的排版方案是正常流排版,它包含了顺次排布和折行等规则。
浏览器支持不同语言,因为不同语言的书写顺序不一致,所以浏览器的文本排版还支持双向文字系统。
浏览器又可以支持元素和文字的混排,元素被定义为占据长方形的区域,还允许边框、边距和留白,这个就是所谓的盒模型。
在正常流的基础上,浏览器还支持两类元素:绝对定位元素和浮动元素。
绝对定位元素把自身从正常流抽出,直接由 top 和 left 等属性确定自身的位置,不参加排版计算,也不影响其它元素。绝对定位元素由 position 属性控制。浮动元素则是使得自己在正常流的位置向左或者向右移动到边界,并且占据一块排版空间。浮动元素由 float 属性控制。
除了正常流,浏览器还支持其它排版方式,比如现在非常常用的 Flex 排版。
根据 CSS 属性对元素逐个进行渲染,得到内存中的位图
浏览器中渲染这个过程,就是把每一个元素对应的盒变成位图。这里的元素包括 HTML 元素和伪元素,一个元素可能对应多个盒。每一个盒对应着一张位图。
渲染过程是非常复杂,但是总体来说,可以分成两个大类:图形和文字,这里不多赘述了。
接着,就是合成
合成的过程,就是为一些元素创建一个“合成后的位图”,把一部分子元素渲染到合成的位图上面。
合成是一个性能考量,那么合成的目标就是提高性能,根据这个目标,我们建立的原则就是最大限度减少绘制次数原则。一个可选的步骤是对位图进行合成,这会极大地增加后续绘制的速度。
合成之后,再绘制到界面上
一般最终位图位于显存中,也有一些情况下,浏览器只需要把内存中的一张位图提交给操作系统或者驱动就可以了,这取决于浏览器运行的环境。不过无论如何,我们把任何位图合成到这个“最终位图”的操作称为绘制。