Skip to content

属性值的计算过程其实就是 CSS 的渲染过程,本文档可以解决读者在练习过程中可能发现的一些奇奇怪怪的 BUG。

首先,一篇 HTML 文档其实是一棵树状结构,浏览器的渲染过程是一个一个渲染,或者说依次渲染,而非同时渲染多个元素。渲染顺序其实就是这棵树的先根遍历序列。这是浏览器总体的渲染流程。

树为数据结构的概念,这里并不深究,可参考数据结构相关知识

如果我们将视角拉到局部,对于单个元素,渲染这个元素的前提是,该元素的所有 CSS 属性必须都有值。任何一个元素的 CSS 属性都非常多,可以去 chrome 调试工具查看:

c878d0ce529d06b74633140344d6a781_MD5

在这里你可以看到这个元素的所有 CSS 属性,读者去看一下也会发现,这里 CSS 属性非常多,并且每一个都有值。但我们并没有给他指定所有的值,我们只写了部分的 CSS 属性,浏览器默认也只规定了部分 CSS 属性,那剩下的 CSS 属性是怎么出来的就成了一个问题。

对于一个元素的每一个属性都是需要计算的,一个元素从什么值都没有到拥有所有属性值,这样一个过程就叫做计算过程,最后得到的值就是计算属性,浏览器就是通过最后得到的计算属性来渲染页面的。 ^9c1a63

综合宏观和微观渲染过程,也就是说,浏览器渲染页面,按照先根遍历序列去渲染,每渲染一个元素都会计算其所有 CSS 属性,然后渲染出来,渲染完毕后继续按照先根遍历序列去渲染下一个元素。

fbda41eb27e69b96df558b68c45a7bd6_MD5

每个元素的属性值的计算过程都分为四步

  • 确定声明值:如果我们为这个属性手动设置了值,或者浏览器的默认样式表给这个元素设置了属性,并且没有冲突,就直接用这个值。
  • 层叠冲突:对于发生了冲突的声明,就会采用 4.层叠(CSS权重)的规则解决冲突,从而确定 CSS 属性值。
  • 使用继承:对于还没有确定属性值的属性,如果这个元素的默认值为 inherit,则会使用父元素的计算属性。
  • 使用默认值:对于还没有确定属性值的属性,如果这个属性默认值不为 inherit,那么直接使用默认值。

浏览器默认样式表和默认值的区别

样式表说白了就是 CSS 文件,程序员自己写的就叫用户样式表,浏览器厂商写的就是浏览器默认样式表,浏览器默认样式表本质上是样式表,也是一个 CSS 文件,是浏览器厂商为了美观自己写的,例如如果没有默认样式表,那么 a 元素的超链接和正文样式就会一模一样,肉眼就无法区分超链接,不同浏览器设置的默认样式表是有区别的。而默认值则是规范规定的,只有当最后确定不出来值的时候才会使用默认值。举个例子,a 元素的默认颜色为纯黑,浏览器厂商觉得这个颜色不好看,一般会写一个 CSS 文件,让 a 元素的颜色变成蓝色。可以将颜色设为 initial,让其还原为默认的纯黑色。

^bfae89

任何一个元素经过以上步骤,都可以获得所有 CSS 属性值。有了这个知识铺垫,就可以解释一些奇奇怪怪的问题。

css
p{
	color:red;
}
html
<p>
	<a>test</a>
</p>

比如上例,为什么 a 元素并没有继承 p 元素的颜色呢?本质上就是因为浏览器默认样式表中给 a 元素设置了一个颜色,既然浏览器默认样式表中设置了 a 元素的颜色,那就会使用样式表中的,而不会使用继承颜色。注意上面的步骤,只有样式表中没有的属性才会考虑继承或者使用默认值。

其实继承和使用默认值是一个过程,继承使用的也是默认值,也就是 inherit,只不过如果默认值为 inherit,会从父元素获取默认值,这里多了一步计算过程。

以笔记为镜,可以知得失