CSS 层叠与继承

这篇文章是写给我自己看的。若是有 CSS 初学者想了解继承与层叠的相关知识,还是去老老实实看书比较好。

当多条规则共同影响一个属性时,判断哪个样式最终会胜出的机制 为层叠(Cascade)


我们先来了解这样一个概念:Specificity。《CSS 权威指南》将其翻译为“特殊性”,《CSS 设计指南》将其翻译为“特指度”。

同一个元素可以被多个规则选择到,每个规则的选择器都有 Specificity,哪条规则的选择器的Specificity 最高,那么该条规则内与其他规则发生冲突的声明的属性值就会胜出,被应用于文档的实际样式表现。


CSS 用“层叠”来解决属性值的冲突,比较选择同一元素的选择器的 Specificity 的高低是“层叠”规则的一部分。

  1. 找出所有相关的规则,这些规则都包含一个与给定元素匹配的选择器。

  2. 按照权重对应用到该元素的所有声明排序。带有 !important 标志的声明的权重高于没有 !important 标志的声明。来自设计者的声明的权重高于用户的声明,但是,有 !important 标志的用户的声明的权重高于其他所有样式的声明(包括有 !important 标志的设计者的声明)。设计者的声明和用户的声明的权重都比用户代理的默认声明高。即:用户!important > 设计者!important > 设计者 > 用户 > 用户代理(浏览器)

  3. 按 Specificity 对应用到给定元素的所有声明排序。有较高 Specificity 的选择器所在的规则的声明胜出。

  4. 若两条或多条声明权重相同、所在规则的选择器的 Specificity 也相同,则按出现顺序对应用到给定元素的所有声明排序。在样式表或文档中靠后出现的声明胜出。如果样式表中有导入样式表,出现在导入样式表中的声明在前,主样式表中的所有声明在后。


那么,怎样判断 Specificity 的高低呢?

选择器的 Specificity 由选择器本身的组件确定,有四部分,如 0, 0, 0, 0。一个选择器的具体 Specificity 如下:

  1. 对于选择器中给定的各个 ID 属性值,加 0, 1, 0, 0

例:

li#answer {color: navy;}  /* 0,1,0,1 */
  1. 对于选择器中给定的各个类属性值、attribute selection(翻译为“属性选择器”比较好,[] 那部分)或伪类,加 0, 0, 1, 0
h2.grape {color: purple;}  /* 0,0,1,1 */
html > body table tr[id="totals"] td ul > li {color: maroon;}  /* 0,0,1,7 */
  1. 对于选择器中给定的各个元素和伪元素,加 0, 0, 0, 1

  2. 结合符(>, +, …)、通配选择器(*)对 Specificity 无贡献。结合符没有 Specificity,而通配选择器的 Specificity 为 0, 0, 0, 0。有但是为0 与 根本没有 有区别。


若是组合规则,需将其拆开再分别计算 Specificity。如:

h1, h2.section {color: silver; background: black;}

the user agent treats it as follows:

h1 {color: silver;}  /* 0,0,0,1 */
h1 {background: black;}  /* 0,0,0,1 */
h2.section {color: silver;}  /* 0,0,1,1 */
h2.section {background: black;}  /* 0,0,1,1 */

ID 选择器 和 指定 id 属性的属性选择器在 Specificity 上有所不同。

html > body table tr[id="totals"] td ul > li {color: maroon;}  /* 0,0,1,7 */
li#answer {color: navy;}  /* 0,1,0,1  (winner) */

The ID selector (#answer) in the second rule contributes 0,1,0,0 to the overall specificity of the selector. In the first rule, however, the attribute selector ([id=”totals”]) contributes 0,0,1,0 to the overall specificity. Thus, given the following rules, the element with an id of meadow will be green:

#meadow {color: green;}  /* 0,1,0,0 */
*[id="meadow"] {color: red;}  /* 0,0,1,0 */

内联声明的 Specificity 为 1, 0, 0, 0,这意味着,即使有 id 属性的元素与某个规则匹配,也必须遵循内联样式声明。

h1#meadow {color: red;}

<h1 id="meadow" style="color: green;">The Meadow Party</h1>

在上述代码中(简写了),h1元素的文本还是绿色。


一般推荐按 link - visited - hover - active (LVHA)的顺序声明链接样式:

:link {color: blue;}
:visited {color: purple;}
:hover {color: red;}
:active {color: orange;}

Thanks to the information in this chapter, you now know that the specificity of all of these selectors is the same: 0,0,1,0. Because they all have the same weight, origin, and specificity, the last one that matches an element will win out. An unvisited link that is being “clicked” is matched by three of the rules—:link, :hover, and :active—so the last one of those three declared will win out. Given the LVHA ordering, :active will win, which is likely what the author intended.

如果按照字母顺序来排列样式,如下:

:active {color: orange;}
:hover {color: red;}
:link {color: blue;}
:visited {color: purple;}

按照这种顺序,任何链接都不会显示 :hover 或 :active 样式,因为 :link 和 :visited 样式后出现,所有链接要么是未访问过的,要么是已访问过的,无一例外,所有,前两条就被覆盖了。

按下面这种顺序声明链接样式,只有未访问的链接会有悬停样式,已访问的链接没有。已访问和未访问的链接都会有激活样式(active)。

:link {color: blue;}
:hover {color: red;}
:visited {color: purple;}
:active {color: orange;}

可以把伪类链接起来,如下,这段代码不需要考虑顺序问题:

:link {color: blue;}
:visited {color: purple;}
:link:hover {color: red;}
:visited:hover {color: gray;}

被应用在某一元素的父元素上的 CSS 规则也被应用于该元素,是为继承(Inheritance)

CSS 中有很多属性可以继承,但并不是全部,大多数框模型属性(包括外边距、内边距、背景和边框)都不能被继承。往往可以用我们的生活常识来判断一个属性是否可以被继承。


现在我们终于可以来解释 有 Specificity 但是为0 与 根本没有 有区别 啦。继承的值根本没有 Specificity,也就是说 0 Specificity 也没有,看下面的代码:

* {color: gray;}
h1#page-title {color: black;}

<h1 id="page-title">Meerkat <em>Central</em></h1>
<p>Welcome to the best place on the web for meerkat information!</p>

你觉得,em 标签内的文本会是什么颜色?

答案是:灰色。Since the universal selector applies to all elements and has zero specificity, its color declaration’s value of gray wins out over the inherited value of black, which has no specificity at all. Therefore, the em element is rendered gray instead of black.


这篇文章虽然短,但真真正正写了好几个小时,现在已经是凌晨 1 点 14 分了。自我感觉,CSS 对我的性格的塑造影响巨大,写这篇文章时,我一次头发都没抓。

《CSS: The Definitive Guide》第 4 版即将出版。

参考资料:

《CSS 权威指南》,《CSS: The Definitive Guide》

《CSS 设计指南》

特别感谢:SafariBooksOnline

Leave a Reply

该博客未开启评论功能。读者可在知乎评论该文章,文章地址:点此访问。读者也可通过 E-mail 与作者讨论相关内容:contact#xiake.me