作者:Jartto's
转发链接:http://jartto.wang/2017/11/13/Exploring-the-principle-of-css-parsing/
作为前端,我们每天都在与CSS打交道,那么CSS的原理是什么呢?
一、浏览器渲染开篇,我们还是不厌其烦的回顾一下浏览器的渲染过程,先上图:

文章插图
正如上图所展示的,我们浏览器渲染过程分为了两条主线:
其一,html Parser 生成的 DOM 树;其二,CSS Parser 生成的 Style Rules ;
在这之后,DOM 树与 Style Rules 会生成一个新的对象,也就是我们常说的 Render Tree 渲染树,结合 Layout 绘制在屏幕上,从而展现出来 。
本文的重点也就集中在第二条分支上,我们来探究一下 CSS 解析原理 。二、Webkit CSS 解析器浏览器 CSS 模块负责 CSS 脚本解析,并为每个 Element 计算出样式 。CSS 模块虽小,但是计算量大,设计不好往往成为浏览器性能的瓶颈 。
CSS 模块在实现上有几个特点:CSS 对象众多(颗粒小而多),计算频繁(为每个 Element 计算样式) 。这些特性决定了 webkit 在实现 CSS 引擎上采取的设计,算法 。如何高效的计算样式是浏览器内核的重点也是难点 。
先来看一张图:

文章插图
Webkit 使用 Flex 和 Bison 解析生成器从 CSS 语法文件中自动生成解析器 。
它们都是将每个 CSS 文件解析为样式表对象,每个对象包含 CSS 规则,CSS 规则对象包含选择器和声明对象,以及其他一些符合 CSS 语法的对象,下图可能会比较明了:

文章插图
Webkit 使用了自动代码生成工具生成了相应的代码,也就是说词法分析和语法分析这部分代码是自动生成的,而 Webkit 中实现的 CallBack 函数就是在 CSSParser 中 。
CSS 的一些解析功能的入口也在此处,它们会调用 lex , parse 等生成代码 。相对的,生成代码中需要的 CallBack 也需要在这里实现 。
举例来说,现在我们来看其中一个回调函数的实现,createStyleRule(),该函数将在一般性的规则需要被建立的时候调用,代码如下:
CSSRule* CSSParser::createStyleRule(CSSSelector* selector) { CSSStyleRule* rule = 0; if (selector) { rule = new CSSStyleRule(styleElement); m_parsedStyleObjects.Append(rule); rule->setSelector(sinkFloatingSelector(selector)); rule->setDeclaration(new CSSMutableStyleDeclaration(rule, parsedProperties, numParsedProperties)); } clearProperties(); return rule; }从该函数的实现可以很清楚的看到,解析器达到某条件需要创建一个 CSSStyleRule 的时候将调用该函数,该函数的功能是创建一个 CSSStyleRule ,并将其添加已解析的样式对象列表 m_parsedStyleObjects 中去,这里的对象就是指的 Rule。那么如此一来,经过这样一番解析后,作为输入的样式表中的所有 Style Rule 将被转化为 Webkit 的内部模型对象 CSSStyleRule 对象,存储在 m_parsedStyleObjects 中,它是一个 Vector 。
但是我们解析所要的结果是什么?【全面详解 CSS 原理】1、通过调用 CSSStyleSheet 的 parseString 函数,将上述 CSS 解析过程启动,解析完一遍后,把 Rule 都存储在对应的 CSSStyleSheet 对象中;
2、由于目前规则依然是不易于处理的,还需要将之转换成 CSSRuleSet 。也就是将所有的纯样式规则存储在对应的集合当中,这种集合的抽象就是 CSSRuleSet;
3、CSSRuleSet 提供了一个 addRulesFromSheet 方法,能将 CSSStyleSheet 中的 rule 转换为 CSSRuleSet 中的 rule ;
4、基于这些个 CSSRuleSet 来决定每个页面中的元素的样式;
三、CSS 选择器解析顺序可能很多同学都知道排版引擎解析 CSS 选择器时是从右往左解析,这是为什么呢?
1、HTML 经过解析生成 DOM Tree(这个我们比较熟悉);而在 CSS 解析完毕后,需要将解析的结果与 DOM Tree 的内容一起进行分析建立一棵 Render Tree,最终用来进行绘图 。Render Tree 中的元素(WebKit 中称为「renderers」,Firefox 下为「frames」)与 DOM 元素相对应,但非一一对应:一个 DOM 元素可能会对应多个 renderer,如文本折行后,不同的「行」会成为 render tree 种不同的 renderer 。也有的 DOM 元素被 Render Tree 完全无视,比如 display:none 的元素 。
推荐阅读
- 9个很棒的CSS边框技巧
- 固态硬盘的功耗和发热详解
- 纯CSS实现几个好看的按钮
- Linux curl 命令详解
- 美国购物攻略大全详解
- 菊花茶的功效与作用禁忌详解,玫瑰花茶的功效与禁忌有哪些
- 上海购物攻略大全详解
- 详解牡丹花茶的冲泡方法,冲泡小诀窍
- 全面的了解高尔夫球杆
- css代码规范工具stylelint
