Chrome渲染过程是反复进行的
渲染过程可以被描述为:将HTML/CSS/JavaScript等数据类型进行转换,并且输入到OpenGL以被调用,以显示像素。
同时,在Chrome渲染过程中,我们还希望获得正确的中间数据结构,以便快速响应之后的更新操作,并能够快速响应JS等的数据查询。
可以将渲染过程分为多个"生命周期阶段",生成这些中间输出。
页面数据解析
在之前的计算机底层知识系列中,我们讲过计算机CPU能直接解释运行的只有本地代码(机器语言)程序。用JS/Java等高级语言编写的源代码,需要通过各自的编译器编译后,转换成本地代码。 (有兴趣的可以翻看之前的文章)。下面的处理过程也是类似的。大家可以进行类推分析。
像HTML/CSS/JS是不能够被浏览器直接识别的,是需要进行格式转换和处理。这里就涉及到编译原理相关的知识点。(后期有打算,写相关的编译原理的文章,我们这里就不展开说明了)
HTML 解析为 DOM
HTML标签通过语意化处理将网页进行了分层处理。
例如,一个 <div> 可能包含两个<p>,每个<p>都带有文本信息。因此,第一步是解析这些标签,构建一个反映这种结构的{文档对象模型|Document Object Model}(简称:DOM)。
何为DOM
{文档对象模型|Document Object Model}是一种用于表示和操作HTML、XML和XHTML文档的编程接口。它将文档解析为一个由{节点|Node}和{对象|Object}组成的树形结构,这个树形结构被称为DOM树。
DOM树的根节点是{文档节点|Document Node},它代表整个文档。文档节点下方是{元素节点| Element Node},表示HTML或XML文档中的标签。元素节点可以包含其他元素节点、{文本节点| Text Node}、{注释节点| Comment Node}等。
每个节点在DOM中都有特定的属性和方法,可以用于访问和操作节点的内容、属性和样式。一些常见的节点类型包括:
- {元素节点| Element Node}:代表
HTML或XML文档中的标签,如<div>、<p>、<a>等。
- 可以通过节点的标签名、属性和子节点等进行操作。
- {文本节点| Text Node}:代表元素节点中的文本内容,即标签之间的文本。
- {注释节点| Comment Node}:代表文档中的注释部分,以
<!--开头和-->结尾。 - {属性节点|Attribute Node}:代表元素节点的属性。
DOM提供了一组API,可以通过这些API来操作和修改DOM树。开发人员可以使用JavaScript或其他支持DOM的编程语言来访问和操作DOM。
通过DOM,我们可以动态地创建、修改、删除和查询文档的元素和内容,从而实现动态的Web页面交互和数据操作。
DOM 反应了包含关系
一个{文档对象模型|Document Object Model}反映了包含关系。
在{文档对象模型|Document Object Model}中,每个HTML元素被表示为一个对象,这些对象之间通过父子关系来表示它们之间的包含关系。
例如,如果有一个包含两个段落的 <div> 元素,那么在DOM中,将会有一个表示 <div> 的对象,它包含两个表示段落的子对象。这样的层次结构可以通过递归方式表示整个文档的层次关系。
DOM的双面性
DOM具有双重功能,既作为页面的内部表示,又作为供JS查询或修改渲染的API。
JavaScript引擎(V8)通过一种称为{绑定|Bindings}的系统,将DOM Web API暴露给开发者。
JavaScript引擎(V8)通过{绑定|Bindings}机制将JavaScript与底层的DOM接口进行连接。这种机制允许开发者使用
JavaScript来操作和操纵Web页面上的元素、样式、事件等。实际上,这些DOM Web API只是对底层
DOM树的操作进行了封装,提供了一种更便捷和直观的方式来与DOM进行交互。
多个DOM树
在同一个文档中可能会存在多个
DOM树。
如上图所示,当我们使用自定义元素,在开启影子模式时,attchShadow({mode:'open'})就会产生多个DOM树。(如果对自定义元素的使用方式不是很明确的同学,可以参考这篇文章)
宿主节点的子元素(在宿主树中)被分配到影子树中的<slot>中。
FlatTreeTraversal从宿主节点向下遍历直至影子节点,同时将<slot>替换为指定的元素。
CSS 解析为 CSSOM
构建完DOM树之后,下一步是处理CSS样式。CSS选择器用于选择DOM元素的子集,以对其添加指定的属性声明。
在处理CSS样式时,浏览器会解析
CSS文件或内联样式,并将样式规则应用于DOM树中的相应元素。CSS选择器用于选择要应用样式的目标元素。
选择器可以根据元素的
标签名、类名、ID、属性等进行匹配,以确定应用哪些样式规则。
这里多啰嗦几句,在CSS重点概念精讲中我们介绍过,选择器。
这里我直接就拿来主义了。
CSS 选择器
选择器(.#[]:::)5个
瞄准目标元素
- 类选择器
- 以
.开头
- ID选择器
#开头- 权重相当高
- ID一般指向唯一元素
- 属性选择器
- 含有
[]的选择器 [title]{}/[title="test"]{}
- 伪类选择器
- 前面有一个冒号(
:)的选择器 :link:选择未被访问的链接:visited:选取已被访问的链接:active:选择活动链接:hover:鼠标指针浮动在上面的元素
- 伪元素选择器
- 有连续两个冒号(
::)的选择器 ::before: 选择器在被选元素的内容前面插入内容::after: 选择器在被选元素的内容后面插入内容
关系选择器 (空格>~+)4个
根据与其他元素的关系选择元素的选择器
- 后代选择器
- 选择所有合乎规则的后代元素
- 空格链接
- 相邻后代选择器
- 仅仅选择合乎规则的儿子元素
- 孙子,重孙子元素忽略
>链接
- 兄弟选择器
- 选择当前元素后面的所有合乎规则的兄弟元素
~链接
- 相邻兄弟选择器
- 仅仅选择当前元素相邻的那个合乎规则的兄弟元素
+链接- 常见的使用场景是,改变紧跟着一个标题的段的某些表现方面
权重
!important(10000)- 内联(
1000)- ID选择器(
0100)- 类选择器(
0010)- 标签选择器(
0001)
上面的优先级计算规则,内联样式的优先级最高,如果外部样式需要覆盖内联样式,就需要使用!important
例如,对于以下CSS规则:
h1 { color: blue; } .my-class { font-size: 16px; }
第一个规则选择所有的 <h1> 元素,并将其文本颜色设置为蓝色。第二个规则选择具有类名为 my-class 的元素,并将其字体大小设置为16像素。
在应用CSS样式时,浏览器会遍历DOM树,匹配元素与选择器,并将相应的样式属性应用于匹配的元素。这样,每个元素都会根据匹配的CSS规则来设置其样式属性,从而实现页面的外观和布局。
通过处理CSS样式,我们可以为网页提供丰富的外观效果、布局和交互特性,使网页更加美观和易于使用。
CSS解析器
{CSS解析器|CSS Parser}会解析所有可达有效的样式表,包括内联样式表( <style>)、外部样式表(styles.css)和浏览器默认样式表。它会将样式规则解析为一个模型(这就是我们常说的CSSOM),其中包含选择器和对应的样式声明。
选择器描述了要应用样式的目标元素样式声明定义了要应用的具体样式属性和值。
解析后的CSSOM包含了这些选择器和声明的组合。
为了提高样式规则的查找效率,{CSS解析器|CSS Parser}会对样式规则进行索引。这样可以快速定位匹配特定选择器的样式规则,而不需要遍历整个样式表。
此外,属性类是在构建时由Python脚本自动生成的。属性类用于在运行时快速查找具有相同样式属性的元素。它们被用作索引的一部分,以便在应用样式时能够高效地定位和处理相同属性的元素。
总而言之,CSS解析器根据活动样式表构建样式规则模型,并通过索引和属性类来优化样式的查找和应用过程。这样可以提高渲染效率,并确保正确地应用样式到文档的各个元素上。
ComputedStyle
在样式解析(或重新计算)过程中,解析器会遍历DOM树中的每个元素,并根据匹配的样式规则计算出每个元素的样式属性的最终值。这些最终值包括继承的值、层叠的值以及通过CSS属性值计算得到的值。
所有计算得到的样式属性值会被存储在 ComputedStyle 对象中。这个对象可以被认为是一个巨大的映射,其中样式属性(如颜色、字体大小、边距等)与其对应的值关联起来。通过查询 ComputedStyle 对象,可以快速获取每个元素的最终样式属性值。
通过样式解析和计算,浏览器可以确定每个元素应用的最终样式,从而实现正确的页面渲染和布局。ComputedStyle 对象在渲染过程中起着重要的作用,为每个元素提供了其最终的样式属性值。
实践验证
我们可以通过Chrome开发者工具可以显示任何DOM元素的ComputedStyle。
也可以通过JavaScript访问,getComputedStyle 是一个用于获取元素计算后的样式的方法。
document.styleSheets:
- 这是一个属性,用于获取文档中
所有的样式表(style sheets)。 - 可以使用
document.styleSheets返回的样式表集合来访问和操作具体的样式表。
window.getComputedStyle(element):
- 这是一个方法,用于获取
指定元素的计算样式(computed style)。 - 可以通过传递元素对象给
getComputedStyle方法来获取该元素应用的最终样式。
document.styleSheets[i].cssRules:
- 这是一个属性,用于获取样式表中的所有规则(rules)。
- 可以使用
cssRules属性返回的规则集合来访问和操作具体的样式规则。
element.style:
- 这是一个属性,用于获取或设置元素的内联样式(inline style)。
- 可以通过
element.style来访问和修改元素的样式属性。
使用 getComputedStyle 的基本语法如下:
var element = document.getElementById("elementId"); var computedStyle = window.getComputedStyle(element);
在上面的代码中,我们首先通过 document.getElementById 方法获取到一个具体的元素,并将其赋值给 element 变量。然后,我们使用 window.getComputedStyle 方法来获取该元素的计算后样式,将其赋值给 computedStyle 变量。
通过 getComputedStyle 获取到的样式是一个 CSSStyleDeclaration 对象,它包含了该元素所有计算后的样式属性和对应的值。
你可以通过以下方式来获取具体的样式属性的值:
var value = computedStyle.getPropertyValue("property");











