《WebKit 技术内幕》之六(2): CSS解释器和样式布局

2 CSS解释器和规则匹配

        在了解了CSS的基本概念之后,下面来理解WebKit如何来解释CSS代码并选择相应的规则。通过介绍WebKit的主要设施帮助理解WebKit的内部工作原理和机制。

2.1 样式的WebKit表示类

        在DOM树中,CSS样式可以包含在“style”元素中或者使用“link”来引用一个CSS文档。对于CSS样式表,不管是内嵌还是外部文档,WebKit都使用CSSStyleSheet类来表示。图描述了WebKit内部是如何表示CSS文档的。

                                         图CSS的内部结构主要类和关系

        一切的起源都是从DOM中的Document类开始。先看Document类之外的左上部分:包括一个DocumentStyleSheetCollection类,该类包含了所有CSS样式表;还包括WebKit的内部表示类CSSStyleSheet,它包含CSS的href、类型、内容等信息。CSS的内容就是样式信息StyleSheetContents,包含了一个样式规则(StyleRuleBase)列表。样式规则被用在CSS的解释器的工作过程中。

        下面的部分WebKit主要是将解释之后的规则组织起来,用于为DOM中的元素匹配相应的规则,从而应用规则中的属性值序列。这一过程的主要负责者是StyleSheetResolver类,它属于Document类,并包含了一个DocumentRuleSets类用来表示多个规则集合(RuleSet)。每个规则集合都是将之前解释之后的结果合并起来,并进行分类,例如id类规则、标签类规则等。至于为什么是多个规则集合,是因为这些规则集合可能源自于默认的规则集合(前面提到过WebKit使用默认的CSS样式信息),或者网页自定义的规则集合等。

        下面让我们更进一步重点介绍样式规则。样式规则是解释器的输出结构,是样式匹配的输入数据。样式规则有很多类型,图描述了这些类和继承关系。

                                图StyleRuleBase和它的子类们

  • Style: 这个是基本类型,大多数规则属于这个类型。
  • lmport: 是WebKit中为了方便而引入的,其对应的是一个导入CSS文件的Style元素。
  • Media: 对应于CSS标准中的@media类型。
  • Fontface: CSS3新引入的自定义字体的规则类型。
  • Page: 对应于CSS标准中的@page类型。
  • Keyframes: 对应于WebKit中的@-webkit-key-frames类型,可以用来定制特定帧的样式属性信息。
  • Region: 对CSS标准正在进行中的Regions的支持,这方便了开发者对页面进行分区域排版。

        这些类基本上跟CSS的标准相对应,当然也有特例,那就是StyleRuleImport,它是WebKit引入的一个新的类型,主要对应的是导入CSS文件的元素。

        接下来剖析规则的内部是如何组成和表示的。图描述的是一个CSS规则(从示例代码中获取)和WebKit的内部结构表示类。

                                图CSS样式规则和WebKit的内部结构表示类

        首先最外层的是样式规则,通常一个样式表可能包括一个或者多个样式规则,这里描述的样式规则对应于图中的StyleRule类。

        然后是选择器部分,图的上半部分是一个选择器列表,这在现实中是比较常见的,因为选择的条件可能有多个。举个例子,“a[class=abc]”其实是两个选择器合起来的,第一个是“a”,它是一个标签选择器;第二个是“[class=abc]”,它是一个属性选择器。这两个选择器合起来的含义就是匹配元素是“a”的标签并且它的类别为“abc”。选择器在WebKit的内部表示是CSSSelector类。在规则中,CSSSelector类使用一个对象列表来表示它们。

        最后是这个规则对应的属性集合CSSPropertySet。WebKit使用了一些类来分别表示属性名字CSSPropertyID (1) 、属性值CSSValue。图6-7清晰地描述了它们的结构。

2.2 解释过程

        CSS解释过程是指从CSS字符串经过CSS解释器处理后变成渲染引擎的内部规则表示的过程。在WebKit中,这一过程如图所示。

                                图CSS解释器的工作过程

        这一过程并不复杂,基本的思想是由CSSParser类负责。CSSParser类其实也是桥接类,实际的解释工作是由CSSGrammer.y.in来完成。CSSGrammer.y.in是Bison的输入文件,Bison是一个生成解释器的工具。Bison根据CSSGrammer.y.in生成CSS解释器——CSSGrammer类。当然CSSGrammer类需要调用CSSParser类来处理解释结果,例如需要使用CSSParser类创建选择器对象、属性、规则等。

        图描述的正是这一过程。当WebKit需要解释CSS内容的时候,它调用CSSParser对象来设置CSSGrammer对象等,解释过程中需要的回调函数由CSSParser来负责处理,最后WebKit将创建好的结果直接设置到StyleSheetContents对象中,这一过程显得直接而且简单。

        在解释网页中自定义的CSS样式之前,实际上WebKit渲染引擎会为每个网页设置一个默认的样式,这决定了网页所没有设置的元素属性及其属性默认值和将要显示的效果。一般来讲,不同的WebKit移植可以设置不同的默认样式。下面是Chrome浏览器使用的默认样式,这些样式决定了默认的网页显示效果。

"html,body,div{display:block}head{display:none}body{margin:8px}div:focus, span:focus{outline:auto 5px-webkit-focus-ring-color}a:-webkit-any-link{color:-webkit-link;text-decoration:underline}a:-webkit-any-link:active{color:-webkit-activelink}"

2.3 样式规则匹配

        样式规则建立完成之后,WebKit保存规则结果在DocumentRuleSets对象类中。当DOM的节点建立之后,WebKit会为其中的一些节点(只限于可视节点,在第7章中介绍)选择合适的样式信息。根据前面的描述,这些工作都是由StyleResolver来负责的。当然,实际的匹配工作还是在DocumentRuleSets类中完成的。

        图描述了参与样式规则匹配的WebKit主要相关类。基本的思路是使用StyleResolver类来为DOM的元素节点匹配样式。StyleResolver类根据元素的信息,例如标签名、类别等,从样式规则中查找最匹配的规则,然后将样式信息保存到新建的RenderStyle对象中。最后,这些RenderStyle对象被RenderObject类所管理和使用。

                                图CSS样式规则匹配使用的主要WebKit类

        规则的匹配则是由ElementRuleCollector类来计算并获得,它根据元素的属性等信息,并从DocumentRuleSets类中获取规则集合,依次按照ID、类别、标签等选择器信息逐次匹配获得元素的样式。那么具体的过程如何呢?图为我们描述了WebKit如何为HTML元素获取样式并从规则集合中匹配的过程。

                        图为HTML元素获取样式和WebKit的样式规则匹配过程

        首先,当WebKit需要为HTML元素创建RenderObject类的时候,首先StyleResolver类负责获取样式信息,并返回RenderStyle对象,RenderStyle对象包含了匹配完的结果样式信息。

        其次,根据实际需求,每个元素可能需要匹配不同来源的规则,依次是用户代理(浏览器)规则集合、用户规则集合和HTML网页中包含的自定义规则集合。这三个规则的匹配方式是类似的,这里是以自定义规则的匹配为例加以说明的。

        再次,对于自定义规则集合,它先查找ID规则,检查有无匹配的规则,之后依次检查类型规则、标签规则等。如果某个规则匹配上该元素,WebKit把这些规则保存到匹配结果中。

        最后,WebKit对这些规则进行排序。对于该元素需要的样式属性,WebKit选择从高优先级规则中选取,并将样式属性值返回。

2.4 实践:样式匹配

为了理解样式的实际匹配过程和结果,以网页“http://lab.hakim.se/reveal-js/”为例,详细的步骤如下。

        首先,打开Chrome浏览器输入上述网页地址,并打开开发者工具,单击“Elements”按钮。

        其次,在开发者工具中单击“打开网页的源代码”按钮,选择“body”元素,在开发者工具的右侧,读者会看到如图6-11左边部分所示经过计算的该元素的匹配结果样式(Computed Style)。用户甚至可以直接在开发者工具中修改属性值,看看它们是如何影响布局的。

                                        图网页的样式计算和规则匹配

               最后,查看一下“styles”中的“Matched CSS Rules”,这些规则能够匹配上该节点的规则列表,但是不同的属性可能来源于不同的规则。在本例中,读者可以看到图中右边的部分就是当前匹配上的各个样式规则,它们来源于不同的CSS样式表中不同的规则。前面四个规则来源于网页自定义的样式表,最后一个“user agent stylesheet”来源于浏览器默认样式表。这些规则中有些对属性的设置有冲突,当然规则按照CSS标准定义的优先级来选择。图中被线划掉的表示该属性没有对当前元素起作用,这包含了两种情形:第一是属性设置错误;第二是被更高优先级的规则属性覆盖。开发者通过元素的具体匹配规则可以调试和修改自己的样式规则。

2.5 JavaScript设置样式

        CSSOM定义了JavaScript访问样式的能力和方式。示例代码6-1中的第29行所示的是使用CSSOM接口来更改属性值的。在WebKit中,这需要JavaScript引擎和渲染引擎协同完成。为了描述这一过程,可能会涉及到一些JavaScript引擎的调用,目前比较难以理解,所以读者只需要有一个大致的印象即可,在第9章的JavaScript引擎中会有更详细和系统的介绍。

        大致的过程是,JavaScript引擎调用设置属性值的公共处理函数,然后该函数调用属性值解析函数,在这个例子中则是CSS的JavaScript绑定函数。而后WebKit将解析后的信息设置到元素的“style”属性的样式“webkitTransform”中,然后设置标记表明该元素需要重新计算样式,并触发重新计算布局。最后就是WebKit的重新绘图,图6-12描述了其中的主要过程。

                                       图WebKit引擎和JavaScript引擎设置样式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/337528.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java数据类型

基本数据类型:(8种) 整型:byte、short、int、long 浮点型:float、double 字符型:char 布尔类型:boolean 1、整数类型(整型) 2、浮点类型 细节:如果是直接查询得到的小数或者直接赋值…

C++入门学习(十)如何显示浮点数的完整形态

在C中&#xff0c;如果你想要显示浮点数的完整数字&#xff08;包括小数部分和指数部分&#xff09;&#xff0c;可以使用 std::setprecision 和 std::fixed 来设置精度和固定小数点表示&#xff1a; #include <iostream> #include <iomanip> // 必须包含这个头…

Python实现离散选择Logit模型(Logit算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 Logit模型&#xff08;Logit model&#xff0c;也译作“评定模型”&#xff0c;“分类评定模型”&…

小程序使用echarts图表-雷达图

本文介绍下小程序中如何使用echarts 如果是通过npm安装&#xff0c;这样是全部安装的&#xff0c;体积有点大 我这边是使用echarts中的一个组件来实现的&#xff0c;下边是具体流程&#xff0c;实际效果是没有外边的红色边框的&#xff0c;加红色边框的效果是这篇说明 1.echa…

测试覆盖与矩阵

4. Coverage - 衡量测试的覆盖率 我们已经掌握了如何进行单元测试。接下来&#xff0c;一个很自然的问题浮现出来&#xff0c;我们如何知道单元测试的质量呢&#xff1f;这就提出了测试覆盖率的概念。覆盖率测量通常用于衡量测试的有效性。它可以显示您的代码的哪些部分已被测…

【SpringBoot技术专题】「开发实战系列」Undertow web容器的入门实战及调优方案精讲

Undertow web容器的入门实战及调优方案精讲 Undertow web容器Undertow 介绍官网API给出一句话概述Undertow&#xff1a;官网API总结特点&#xff1a;Lightweight&#xff08;轻量级&#xff09;HTTP Upgrade Support&#xff08;支持http升级&#xff09;、HTTP/2 Support支持H…

【Linux 内核源码分析】堆内存管理

堆 堆是一种动态分配内存的数据结构&#xff0c;用于存储和管理动态分配的对象。它是一块连续的内存空间&#xff0c;用于存储程序运行时动态申请的内存。 堆可以被看作是一个由各个内存块组成的堆栈&#xff0c;其中每个内存块都有一个地址指针&#xff0c;指向下一个内存块…

学生公寓智能控电系统的重要性

学生公寓智能控电系统石家庄光大远通电气有限公司学生宿舍内漏电&#xff0c;超负荷用电&#xff0c;违规用电等现象一直是困扰后勤管理的普遍问题。随着学生日常生活方式以及生活用品的改变&#xff0c;电脑以及各种电器逐渐的普及&#xff0c;导致用电量与日俱增&#xff0c;…

竞赛保研 机器视觉人体跌倒检测系统 - opencv python

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 机器视觉人体跌倒检测系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&…

翻译: Anaconda 与 miniconda的区别

Anaconda 和 miniconda 是广泛用于数据科学的软件发行版&#xff0c;用于简化包管理和部署。 1. 主要有两个区别&#xff1a; packages包数量&#xff1a; Anaconda 附带了 150 多个数据科学包&#xff0c;而 miniconda 只有少数几个。Interface接口&#xff1a;Anaconda 有…

mfc110.dll丢失是什么意思?全面解析mfc110.dll丢失的解决方法

在使用计算机的过程中&#xff0c;用户可能会遭遇一个常见的困扰&#xff0c;即系统提示无法找到mfc110.dll文件。这个动态链接库文件&#xff08;DLL&#xff09;是Microsoft Foundation Classes&#xff08;MFC&#xff09;库的重要组成部分&#xff0c;对于许多基于Windows的…

node.js项目express的初始化

目录 1.初始化项目2.配置跨域3.开始编写API3.1准备3.2路由处理函数router_make下的user.js3.3路由模块router下的user.js3.4入口文件app.js里面去新增这段代码3.5启动项目进行测试 &#x1f44d; 点赞&#xff0c;你的认可是我创作的动力&#xff01; ⭐️ 收藏&#xff0c;你…

设备管理——WinCC 给你神助功

要实现“设备高效”&#xff0c;就必须“管之有道”&#xff0c;来自设备层的数据支撑将是必不可少的&#xff0c;提高设备效能的2个关键在于降低平时停机时间 (MDT) 和提高平均无故障时间 (MTBF)。通常来说&#xff0c;设备维护可大致可分为三个层次&#xff1a;纠正性维护&am…

[Tool] python项目中集成使用Firebase推送功能

背景介绍 目前&#xff0c;App推送功能已经非常普遍&#xff0c;几乎所有App都有推送功能。推送功能可以自己实现&#xff0c;也可以使用第三方提供的推送服务&#xff08;免费的收费的都有&#xff09;。本文主要介绍使用Firebase提供的推送服务Firebase Cloud Messaging&…

matlab appdesigner系列-常用13-标签

标签&#xff0c;用来显示各类文本 此示例&#xff0c;就是在标签之外的画布上单击鼠标左键&#xff0c;显示王勃的《滕王阁诗》 操作如下&#xff1a; 1&#xff09;将2个标签拖拽到画布上&#xff0c;并修改相应文字。将第二个标签的右侧文本信息中的Wordwrap打开&#xf…

[自动化分布式] Zabbix自动发现与自动注册

abbix 自动发现&#xff08;对于 agent2 是被动模式&#xff09; zabbix server 主动的去发现所有的客户端&#xff0c;然后将客户端的信息登记在服务端上。 缺点是如果定义的网段中的主机数量多&#xff0c;zabbix server 登记耗时较久&#xff0c;且压力会较大 部署 添加zabb…

六、标准对话框、多应用窗体

一、标准对话框 Qt提供了一些常用的标准对话框&#xff0c;如打开文件对话框、选择颜色对话框、信息提示和确认选择对话框、标准输入对话框等。1、预定义标准对话框 &#xff08;1&#xff09;QFileDialog 文件对话框 QString getOpenFileName() 打开一个文件QstringList ge…

uniapp组件库Popup 弹出层 的使用方法

目录 #平台差异说明 #基本使用 #设置弹出层的方向 #设置弹出层的圆角 #控制弹窗的宽度 | 高度 #内容局部滚动 #API #Props #Event 弹出层容器&#xff0c;用于展示弹窗、信息提示等内容&#xff0c;支持上、下、左、右和中部弹出。组件只提供容器&#xff0c;内部内容…

树的一些经典 Oj题 讲解

关于树的遍历 先序遍历 我们知道 树的遍历有 前序遍历 中序遍历 后序遍历 然后我们如果用递归的方式去解决&#xff0c;对我们来说应该是轻而易举的吧&#xff01;那我们今天要讲用迭代&#xff08;非递归&#xff09;实现 树的相关遍历 首先呢 我们得知道 迭代解法 本质上也…

【征服Redis12】redis的主从复制问题

从现在开始&#xff0c;我们来讨论redis集群的问题&#xff0c;在前面我们介绍了RDB和AOF两种同步机制&#xff0c;那你是否考虑过这两个机制有什么用呢&#xff1f;其中的一个重要作用就是为了集群同步设计的。 Redis是一个高性能的键值存储系统&#xff0c;广泛应用于Web应用…