由第2章得知,我们可以使用多种不同的方法选择元素。实际上,同一个元素可能会被两个或多个规则选择,而且每个规则的选择符不尽相同。
h1 {color: red;}
body h1 {color: green;}
h2.grape {color: purple;}
h2 {color: silver;}
html > body table tr[id=”totals”] td ul > li {color: maroon;}
li#answer {color: navy;}
每对规则中只有一个能胜出,因为匹配的元素只能显示为其中一个颜色。那么我们如何知道哪个规则胜出呢?
答案隐藏在每个选择符的特指度中。用户代理会计算每个规则中选择符的特指度,然后将其依附到规则中的每个声明上。如果两个或多个属性声明有冲突,特指度最高的声明胜出。
选择符的特指度由选择符本身的组成部分决定。一个特指度值由四部分构成,例如0,0,0,0。选择符的特指度通过下述规则确定:
- 选择符中的每个ID属性值加0,1,0,0。
- 选择符中的每个类属性值、属性选择或伪类加0,0,1,0。
- 选择符中的每个元素和伪元素加0,0,0,1。伪类到底有没有特指度在CSS2中表述的有些自相矛盾,不过1明确指出,伪元素有特指度。
- 连结符和通用选择符不增加特指度。
例如,下面给出几个规则中选择符的特指度:
h1 {color: red;} /* specificity = 0,0,0,1 */
p em {color: purple;} /* specificity = 0,0,0,2 */
.grape {color: purple;} /* specificity = 0,0,1,0 */
*.bright {color: yellow;} /* specificity = 0,0,1,0 */
p.bright em.dark {color: maroon;} /* specificity = 0,0,2,2 */
#id216 {color: blue;} /* specificity = 0,1,0,0 */
div#sidebar *[href] {color: silver;} /* specificity = 0,1,1,1 */
现在做一个练习,计算本节开头那几对规则的特指度:
h1 {color: red;} /* 0,0,0,1 */
body h1 {color: green;} /* 0,0,0,2 (winner)*/
h2.grape {color: purple;} /* 0,0,1,1 (winner) */
h2 {color: silver;} /* 0,0,0,1 */
html > body table tr[id=”totals”] td ul > li {color: maroon;} /* 0,0,1,7 */
li#answer {color: navy;} /* 0,1,0,1 (winner) */
我已经指出每一对中的胜者,即特指度较高的规则。注意特指度的比较方式。在第二对中,h2.grape选择符胜出,因为它多一个1,0,0,1,1大于0,0,0,1。在第三对中,后一个规则胜出,因为0,1,0,1大于0,0,1,7。特指度值0,0,1,0其实比0,0,0,13大。
3.1.1声明和特指度
选择符的特指度确定之后,其值将赋予关联的每个声明。对下述规则来说:
h1 {color: silver; background: black;}
为了计算特指度,用户代理必须把规则“打散”成单独的规则。因此,上述规则将变成:
h1 {color: silver;}
h1 {background: black;}
二者的特指度都是0,0,0,1,赋予每个声明的值就是它。群组选择符也有这样的打散过程。对下述规则来说:
h1, h2.section {color: silver; background: black;}
在用户代理看来是这样的:
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 */
如果多个规则匹配同一个元素,而且部分声明之间有冲突,特指度就发挥作用了。例如,对下面的规则来说:
h1 + p {color: black; font-style: italic;} /* 0,0,0,2 */
p {color: gray; background: white; font-style: normal;} /* 0,0,0,1 */
*.aside {color: black; background: silver;} /* 0,0,1,0 */
应用到下述标记后渲染得到的结果如图3-1所示。
<h1>Greetings!</h1>
<p class=”aside”>
It’s a fine way to start a day, don’t you think?
</p>
<p>
There are many ways to greet a person, but the words are not as important as the act of greeting itself.
</p>
<h1>Salutations!</h1>
<p>
There is nothing finer than a hearty welcome from one’s fellow man.
</p>
<p class=”aside”>
Although a thick and juicy hamburger with bacon and mushrooms runs a close second.
</p>
图3-1:不同规则对文档的影响
在任何情况下,用户代理都会确定哪些规则与元素匹配,然后找出所有相关的声明,计算各自的特指度,判断哪些规则胜出,再把胜出的规则应用到元素上,得到装饰后的结果。每个元素、选择符和声明都要经历这一系列操作。幸好,用户代理能自动处理一切。这个行为是层叠的重要部分。
3.1.2通用选择符的特指度
通用选择符不增加特指度。也就是说,它的特指度为0,0,0,0,这与没有特指度是不同的(参见3.2节)。因此,对下面两个规则来说,div元素中的段落将显示为黑色,其他元素则显示为灰色:
div p {color: black;} /* 0,0,0,2 */
* {color: gray;} /* 0,0,0,0 */
你可能猜到了,包含通用选择符的选择符,它的特指度不因有通用选择符的存在而改变。下面两个选择符的特指度相等:
div p /* 0,0,0,2 */
body * strong /* 0,0,0,2 */
连结符不同,它根本没有特指度,即连零都没有。因此,连结符对选择符的总特指度没有影响。
3.1.3 ID和属性选择符的特指度
ID选择符和选择id属性的属性选择符之间在特指度上是有区别的,这一点一定要注意。来看前述示例中的第三对规则:
html > body table tr[id=”totals”] td ul > li {color: maroon;} /* 0,0,1,7 */
li#answer {color: navy;} /* 0,1,0,1 (wins) */
第二个规则中的ID选择符(#answer)为选择符的总特指度贡献0,1,0,0。然而,第一个规则中的属性选择符([id=”totals”])为总特指度贡献0,0,1,0。因此,对下述规则来说,id为meadow的元素将显示为绿色:
#meadow {color: green;} /* 0,1,0,0 */
*[id=”meadow”] {color: red;} /* 0,0,1,0 */
3.1.4行内样式的特指度
目前见到的特指度都以零开头,因此你可能在想,那一位为什么要存在呢?存在必定有用。那一位是为行内样式声明保留的,行内样式声明的特指度比其他声明都高。对下面的规则和标记片段来说:
h1 {color: red;}
<h1 style=”color: green;”>The Meadow Party</h1>
即便那个规则会应用到h1元素上,但是h1元素中的文本仍将显示为绿色。这是因为行内声明的特指度为1,0,0,0。
3.1.5重要性
有时某个声明可能非常重要,超过其他所有声明。CSS称之为重要声明(important declaration,原因显而易见)。这种声明要在声明末尾的分号之前插入!important,例如:
p.dark {color: #333 !important; background: white;}
这里,颜色值#333使用!important标记,而背景色white没有。如果想把两个声明都标记为重要的,每个声明中都要插入!important:
p.dark {color: #333 !important; background: white;}
!important的位置必须正确,否则声明将失效。!important始终放在声明末尾的分号之前。对值为多个关键字的属性(例如font)来说,!important的位置尤其重要:
p.dark {color: #333 !important; background: white !important;}
带有!important的声明对特指度没有影响,但是会与不重要的声明分开处理。其实,所有带 !important的声明会放在一起,而特指度冲突就在这个范围内解决。同样,非重要的声明作为一个整体,其中的冲突使用特指度解决。因此,重要声明和非重要声明冲突时,重要声明始终胜出。
下述规则和标记片段的结果如图3-2所示。
h1 {font-style: italic; color: gray !important;}
.title {color: black; background: silver;}
* {background: black !important;}
<h1 class=”title”>NightWing</h1>
图3-2: 重要规则始终胜出