浏览器解释并显示 HTML 文件的方式是在 HTML 和 CSS 规范中指定的。这些规范由网络标准化组织 W3C(万维网联盟)进行维护。
浏览器的用户界面并没有任何正式的规范,这是多年来的最佳实践自然发展以及彼此之间相互模仿的结果。
浏览器的组成
- 用户界面 : 包括地址栏、前进/后退按钮、书签菜单等。除了浏览器主窗口显示的您请求的页面外,其他显示的各个部分都属于用户界面。
- 浏览器引擎: 在用户界面和呈现引擎之间传送指令。
- 呈现引擎: 负责显示请求的内容。如果请求的内容是 HTML,它就负责解析 HTML 和 CSS 内容,并将解析后的内容显示在屏幕上。
- 网络: 用于网络调用,比如 HTTP 请求。其接口与平台无关,并为所有平台提供底层实现。
- 用户界面后端: 用于绘制基本的窗口小部件,比如组合框和窗口。其公开了与平台无关的通用接口,而在底层使用操作系统的用户界面方法。
- JavaScript 解释器: 用于解析和执行 JavaScript 代码。
- 数据存储: 这是持久层。浏览器需要在硬盘上保存各种数据,例如 Cookie。新的 HTML 规范 (HTML5) 定义了“网络数据库”,这是一个完整(但是轻便)的浏览器内数据库。
本篇重点讲述 呈现引擎 的一些规则
呈现流程(呈现引擎)
1 | 1. 处理 HTML 标记,构建 DOM 树。(字节数据-字符串-Token-Node-Dom) |
⚠️ css文件不会阻塞html的解析,但是会阻塞html的渲染, 而js会阻塞解析。
虽然浏览器内部十分复杂,对于呈现来说, HTML 和 CSS 解析器相对于一般的语法解析还是不一样的。
- HTML 解析器
HTML 和 XML 非常相似。有很多 XML 解析器可以使用。HTML 存在一个 XML 变体 (XHTML),那么有什么大的区别呢?区别在于 HTML 的处理更为“宽容”,它允许您省略某些隐式添加的标记,有时还能省略一些起始或者结束标记等等。和 XML 严格的语法不同,HTML 整体来看是一种“软性”的语法。
简单看一下HTML的解析算法:
比如:
1 | <html> |
初始状态是数据状态。遇到字符 < 时,状态更改为“标记打开状态”。接收一个 a-z 字符会创建“起始标记”,状态更改为“标记名称状态”。这个状态会一直保持到接收 > 字符。在此期间接收的每个字符都会附加到新的标记名称上。在本例中,我们创建的标记是 html 标记。
遇到 > 标记时,会发送当前的标记,状态改回“数据状态”。
标记也会进行同样的处理。目前 html 和 body 标记均已发出。现在我们回到“数据状态”。接收到 Hello world 中的 H 字符时,将创建并发送字符标记,直到接收 中的 <。我们将为 Hello world 中的每个字符都发送一个字符标记。现在我们回到“标记打开状态”。接收下一个输入字符 / 时,会创建 end tag token 并改为“标记名称状态”。我们会再次保持这个状态,直到接收 >。然后将发送新的标记,并回到“数据状态”。 输入也会进行同样的处理。
- CSS树的构建
和 HTML 不同,CSS 是上下文无关的语法,可以使用简介中描述的各种解析器进行解析。
- 呈现树的构建
WebKits RenderObject 类是所有呈现器的基类
1 | class RenderObject { |
下面这段 WebKit 代码描述了根据 display 属性的不同,针对同一个 DOM 节点应创建什么类型的呈现器。
1 | RenderObject* RenderObject::createObject(Node* node, RenderStyle* style) |
所以这就解释了为什么当 display: none;
时, 元素是不占物理空间的。
reflow AND repaint
reflow(回流)
浏览器为了
重新渲染部分或整个页面
,重新计算页面元素位置和几何结构的进程叫做reflow
- 什么时候会导致reflow发生呢?
1 | - 改变窗口大小 |
1 | 🌝🌝插播一个问题 :如何插入几万个 DOM,如何实现页面不卡顿? |
- reflow优化建议
1 | - 不要一条一条地修改 DOM 的样式,预先定义好 class,然后修改 DOM 的 className |
repaint
屏幕的一部分要重画,比如某个CSS的背景色变了。但是元素的几何尺寸没有变。是在一个元素的外观被改变,但没有改变布局的情况下发生的当repaint发生时,浏览器会验证DOM树上所有其他节点的visibility 属性。
常见的重绘元素:
color
border-style
visibility
background
text-decoration
background-image
background-position
background-repeat
outline-color
border-radius
box-shadow
…
CSS高消耗属性
1 | - box-shadows |
CSS2 规范定义了绘制流程的顺序。绘制的顺序其实就是元素进入堆栈样式上下文的顺序。这些堆栈会从后往前绘制,因此这样的顺序会影响绘制。块呈现器的堆栈顺序如下:
1 | 1. 背景颜色 |
事件执行机制相关
- 当 Event loop 执行完
Microtasks
后,会判断 document 是否需要更新。因为浏览器是 60Hz 的刷新率,每 16ms 才会更新一次。
然后判断是否有resize
或者scroll
,有的话会去触发事件,所以 resize 和 scroll 事件也是至少 16ms 才会触发一次,并且自带节流功能。 - 判断是否触发了
media query
- 更新动画并且发送事件
- 判断是否有全屏操作事件
- 执行
requestAnimationFrame
回调 - 执行
IntersectionObserver
回调,该方法用于判断元素是否可见,可以用于懒加载上,但是兼容性不好 - 更新界面
以上就是一帧中可能会做的事情。如果在一帧中有空闲时间,就会去执行requestIdleCallback
回调。
最后: 还是抛出一个常见的问题:
Q: 当浏览器输入URL后发生了什么?
A: