从Chrome源码看浏览器如何计算CSS

浏览器构建DOM的方式如下:浏览器每收到一段HTML的文本之后,就会把它序列化成一个个的tokens,依次遍历这些token,实例化成对应的HTML节点并插入到DOM树里面

加载CSS

在构建DOM的过程中,如果遇到link的标签,当把它插到DOM里面之后,就会触发资源加载——根据href 的链接

   <link rel="stylesheet" href="demo.css">
   
   
  • 1
  • 1

上面的rel指明了它是一个样式文件。这个加载是异步,不会像加载js一样影响DOM树的构建。只是说在CSS没处理好之前,构建好的DOM并不会显示出来。
从打印的log可以看出(添加打印的源码略):
这里写图片描述
在CSS没有加载好之前,DOM树已经构建好了,为什么DOM构建好了不把HTML放出来,因为没有样式的HTML直接放出来,给人看到的页面将会是乱的。所以一旦CSS太大,页面一打开将会停留较长时间的白屏。所以如果把图片/字体等转成base64放到CSS里面,会让CSS过大导致白屏幕(原本图片和字体在CSS加载中是异步加载)

解析CSS

(1)字符串 -> tokens

这里写图片描述
经常看到有人建议CSS的色值使用16位的数字会优于使用rgb的表示,如果改成rgb,它将变成一个函数类型的token,这个函数需要再计算一下,所以使用16位色值确实比使用rgb好。
(2)tokens -> styleRule
这里不关心它是怎么把tokens转化成style的规则的,我们只要看格式化后的styleRule是怎么样的就可以。每个styleRule主要包含两个部分,一个是选择器selectors,第二个是属性集properties。

这里写图片描述

打印出来的选择器结果为(相关打印代码省略):

这里写图片描述

从第一个选择器可以看出,它的解析是从右往左的,这个在判断match的时候比较有用(先解析了hello再解析text)。
设置了margin: 20px,会转化成四个属性。所以CSS提倡属性合并,但是最后还是会被拆成各个小属性。所以属性合并最大的作用应该在于减少CSS的代码量。
一个选择器和一个属性集就构成一条rule,同一个css表的所有rule放到同一个stylesheet对象里面
(3).生成哈希map
最后会把生成的rule集放到四个类型哈希map,map的类型是根据最右边的selector的类型:id、class、标签、伪类选择器区分的,这样做的目的是为了在比较的时候能够很快地取出匹配选择器的所有rule,然后每条rule再检查它的下一个selector(向左查找)是否匹配元素。
译者注: 比如同一个.text 元素,一个样式是ul 中的.text ,一个样式是div 中的.text ,只需要记录.text 的样式在哈希map中,至于是匹配div还是ul中的样式,由下一步计算CSS来做
到这里,就完成了一个表到一个对象树的映射。

计算CSS

CSS表解析好之后,会触发layout tree,进行layout的时候,会把每个可视的Node结点相应地创建一个Layout结点,而创建Layout结点的时候需要计算一下得到它的style。为什么需要计算style,因为可能会有多个选择器的样式命中了它,所以需要把几个选择器的样式属性综合在一起,以及继承父元素的属性以及UA的提供的属性。这个过程包括两步:找到命中的选择器和设置样式。

这里写图片描述

上面会生成两个rule,第一个rule会放到上面提到的四个哈希map其中的classRules里面,而第二个rule会放到tagRules里面。
当这个样式表解析好时,触发layout,这个layout会更新所有的DOM元素。这是一个递归,初始为document对象,即从document开始深度优先,遍历所有的dom结点,更新它们的布局。
在遇到div.text这个元素的时候,会去执行上面代码的取出classRules的那行。
到了检验p标签的时候,会取出”.text p”的rule,它的第一个选择器是p,将会在上面代码的第3行判断成立。但由于它前面还有限定,于是它还得继续检验前面的限定成不成立。
由于这里是一个后代选择器,所以它会循环当前元素所有父结点,用这个父结点和第二个选择器”.text”,并且它已经是最后一个选择器了,所以判断结束,返回成功匹配。
所以不提倡把选择器写得太长,特别是用sass/less写的时候,新手很容易写嵌套很多层,这样会增加查找匹配的负担。例如上面,它需要对下一个父代选器启动一个新的递归的过程,而递归是一种比较耗时的操作。一般是不要超过三层。

转自:http://blog.csdn.net/sysuzhyupeng/article/details/60464810

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值