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");