版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/caomage/article/details/102217809
从整个网页的加载和渲染过程来看,CSS解释器和规则匹配处于DOM树建立之后,RenderObject树(下一篇文章会介绍)建立之前,CSS解释器解释后的结果会保存起来,然后RenderObject树基于该结果进行规则匹配和布局计算。当网页有用户交互或者动画等动作的时候,通过CSSOM技术,JavaScript代码同样可以很方便的修改CSS样式,Webkit此时需要重新解释样式并重复以上这一过程。
通常我们的CSS代码都是静态的,那么CSS有没有提供一些方法可以让开发者写一些脚本去操作它呢?这就是CSSOM,成为CSS对象模型。它的思想是在DOM中的一些节点接口中,加入获取和操作CSS属性或者接口的JavaScript接口。因而JavaScript可以动态操作CSS样式。
对于内部和外部样式表,CSSOM定义了样式表的接口,称为CSSStyleSheet,这是一个可以在JavaScript代码中访问的接口。借助于该接口,开发者可以在JavaScript中获取样式表的各种信息,例如CSS的href、样式表类型type、规则信息cssRules等,甚至可以获取样式表中的CSS规则列表。这个接口同DOM中的Script或者Link节点不一样,它是CSSOM定义的心接口。开发者可以通过document.stylesheets
查看当前网页中包含的所有CSS样式表,这是因为CSSOM对DOM中的Document接口进行了扩展。
W3C还定义了另一个规范,那就是CSSOM View,它的基本含义是增加一些新的属性到Window、Document、Element、HTMLElement和MouseEvent等接口,用于表示跟视图相关的特征,例如窗口大小、网页滚动位置、元素的位置、鼠标事件的坐标等信息。
接下来看一下Webkit如何解释CSS代码并选择相应的规则。
CSS解释器是指从CSS字符串经过CSS解释器处理后变成渲染引擎的内部规则表示的过程。这一过程并不复杂,基本的思想是由CSSParser类负责。当Webkit需要解释CSS内容的时候,调用CSSParser来负责,最后Webkit将创建好的结构设置到StyleSheetContents对象中。
在解释网页中自定义的CSS样式之前,实际上Webkit渲染引擎会为每个网页设置一个默认的样式,这决定了网页所没有设置的元素属性及其属性默认值和将要显示的效果。一般来讲,不同的Webkit移植可以设置不同的默认样式。
样式规则建立完成之后,Webkit保存规则结构在DocumentRuleSets对象中。当DOM的节点建立之后,Webkit会为其中的一些节点(可视节点)选择合适的样式信息。这些工作都是由StyleResolver负责。
基本的思路是使用StyleResolver来为DOM的元素节点匹配样式。StyleResolver类根据元素的信息,例如Tag Name、Class等,从样式规则中查找最匹配的规则,然后将样式信息保存到新建的RenderStyle中。最后这些RenderStyle对象被RenderObject使用。
样式的匹配则是由ElementRuleCollector来计算并获得,它根据元素的属性等信息,从之前的DocumentRuleSets中获取规则集合,依次按照ID、Class、Tag等选择器信息逐次匹配获得元素的样式。具体的过程是:
CSSOM定义了JavaScript访问样式的能力和方式。在Webkit中,这需要JavaScript引擎和渲染引擎共同来完成。之后的文章会详细介绍JavaScript引擎。
大致的过程是,JavaScript引擎调用设置属性值的公共处理函数,然后该函数调用属性值解析函数。而后Webkit将解析后的信息设置到元素的style属性的样式webkitTransform中,然后设置标记表明该元素需要重新计算样式,并触发重新布局。最后就是Webkit的重新绘制。
当Webkit创建RenderObject对象之后,每个对象是不知道自己的位置、大小等信息的,Webkit根据盒模型来计算它们的位置大小信息的过程称为布局计算(排版)。
布局计算根据其计算的范围大致可以分为两类:
overflow:auto;
,这种情况一般是其子树布局的改变不会影响其周围元素的布局,因而不需要重新计算更大范围内的布局。布局计算是一个递归的过程,因为一个节点的大小通常需要先计算它的子女节点的位置、大小等信息。RenderObject节点计算布局的主要逻辑都是由RenderObject的layout函数来完成,大致过程如图:
overflow:visible
或者overflow:visible
,Webkit会提供滚动条来保证可以显示所有内容,一般来说页面元素的宽高是在布局的时候通过相关计算得出来的。如果元素由子女,则Webkit需要递归这一过程;哪些情况下需要重新计算布局呢?总体来讲,只要样式发生变化,Webkit都需要重新计算,有以下一些情况:
CSS的布局计算是以包含块和盒模型为基础的,这表示这些元素的布局计算都依赖于块。但是,CSS标准也规定了行内元素,它们和块元素显示不太一样的是它们不会独占一行,而是在行内显示。为此,Webkit的处理方式是–对于一个块元素对应的RenderObject对象,它的子女要么都是块元素的RenderObject对象,要么都是非行内元素的RenderObject,这可以通过建立匿名块(Anonymous Blok)对象来实现,下一篇文章会介绍。
此外,布局计算是比较耗时间的,更糟糕的是,一旦布局发生变化,Webkit可能需要后面的重新绘制操作。