css-结构和层叠

前言

每个合法的文档都会生成一个结构树,了解这一点,就能根据元素的祖先,属性,兄弟元素等等创建选择器来选择元素。有了这个结构树,选择器才能起作用,这也是css另一个重要的方面(继承)的核心。

继承(Inheritance)是从一个元素向其后代元素传递属性值所采用的机制。确定应当向一个元素应用哪些值时,用户代理不仅要考虑继承,还要考虑声明的特殊性,另外需要考虑声明本身的来源。这个过程就称为层叠(cascade)。

——《css权威指南》

特殊性

每个种类的选择器都对应一个特殊性(specificity)。对于每个规则,用户代理会计算选择器的特殊性,并将这个非特殊性附加到规则中的各个声明。如果一个元素有2个或者多个属性声明,那么有最高特殊性的声明就会胜出。(实际上,所有样式冲突的解决都是由层叠来处理的)

特殊性的规则

选择器的特殊性由选择器本身的组件决定的。特殊值表述为4个部分,如0,0,0,0。一个选择器的具体特殊性如下确定:

  1. 对于选择器中给定的各个ID属性(ID选择器)值,加0,1,0,0
  2. 对于选择器中给定的各个类属性(类选择器)值,属性选择(属性选择器)或伪类(伪类选择器),加0,0,1,0
  3. 对于选择器中给定的各个元素和伪元素,加0,0,0,1
  4. 结合符和通配符选择器对特殊性没什么贡献。
  5. 是不是发现还有1,0,0,0这个没有用到,这个是css2.1新增的,是内联样式声明的特殊性。他与ID选择器的特殊性相同,所以ID选择器很容易覆盖内联样式。
  6. 例子:1,0,0,0的优先级大于0,10,0,0

重要性

有时候某个声明可能非常重要,超过了所有其他生命。css2.1称之为重要声明,并允许在这些声明的结束分号之前插入!important来标志。!important总是放在声明的最后,即分号之前。重要规则总会胜出。

1
p{color: red !important;}

继承

关于样式继承

特殊性对于理解如何向文档应用声明很重要,同样的,还有一个很重要的概念,继承。基于继承机制,样式不仅应用到指定的元素,还会应用到他的后代元素。例如,如果向一个h1元素应用一个颜色,那么这个颜色将应用到h1中的所有文本,甚至应用到该h1的子元素的文本。

无法继承的属性

大多数框模型属性是无法继承的,包括边距,内边距,背景个边框。原因很简单,归于一个简单的常识,假设border能继承,那么举个例子:

1
2
3
4
5
6
7
8
<style>
p{
border: 1px solid red;
width: 100px;
color: blue;
}
</style>
<p>hello<span style="border: 1px solid red;">world</span></p>

如果能继承,那么效果如下:

image.png

子元素也多了个框,这明显不是我们想要的,而且我们还要想办法去清除这个内部框。

所以正确的效果如下:

image.png

层叠

为什么需要层叠

层叠式为了解决一个问题:如果遇到两个特殊性相等的规则,要如何抉择。

层叠的规则

css所给予的方法就是让样式层叠在一起,这是通过结合继承和特殊性做到的。规则如下:

按权重和来源排序

如果两个样式规则应用到同一个元素,而且其中一个规则有!important标志,这个重要规则将胜出。在声明权重方面要考虑5级,权重由大到小的顺序依次为:

  1. 读者的重要声明。(用户自定义配置样式)
  2. 创作人员的重要声明
  3. 创作人员的正常声明
  4. 读者的正常声明
  5. 用户代理声明
按特殊性排序

最特殊的声明最优先。例子:1,0,0,0的优先级大于0,10,0,0

按顺序排序

如果2个规则的权重,来源和特殊性完全相同,那么在样式表中最后一个出现的会胜出css2.1中内联样式声明的特殊性要高于所有样式表选择器

正是由于这种按顺序排序,所以才有了通常推荐的链接样式顺序。一般建议按link-visited-hover-active(LVHA)的顺序声明链接样式如下:

1
2
3
4
:link{color: blue;}
:visited{color: purple;}
:hover{color: red;}
:active{color: orange;}

这些选择器的特殊性都是一样的:0,0,1,0。因为他们都有相同的权重、来源和特殊性,因此与元素匹配的最后一个选择器才会胜出。正在”点击”的未访问链接可以与其中3个规则匹配——:link,:hover,:active,所以在这三个规则中最后声明的一个将胜出。如果按照LVHA顺序,:active会胜出,这就是我们所期望的。