[css选择器] 选择器特殊性

选择器特殊性

原文链接: 《CSS权威指南第 3 版》69页-73 页

特殊性

可以使用多种不同的方法选择元素。实际上,可能同一个元素可以使用两个或多个规则来选择,每个规则都有其自己的选择器。下面考虑以下 3 对规则。假设每一对规则都匹配同样的元素:

/* 第一对规则 */
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;
}

显然,每一对规则中只有一个胜出,因为所匹配的元素只能是某一种颜色(或此或彼)。那么怎么知道哪一个规则更强呢?

答案就在于每个选择器的特殊性(specificity)。对于每个规则,用户代理(浏览器)会计算选择器的特殊性,并将这个特殊性附加到规则中的各个声明。如果一个元素有两个或多个冲突的属性声明,那么有最高特殊性的声明就会胜出。

注:这并不是解决冲突的全部。实际上,所有样式冲突的解决都由层叠来处理,本章后面专设了一节介绍这个内容。

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

  • 对于选择器中给定的各个 ID 属性值,加 0, 1, 0, 0。
  • 对于选择器中给定的各个类属性值、属性选择或伪类,加 0, 0, 1, 0。
  • 对于选择器中给定的各个元素和伪元素,加 0, 0, 0, 1。伪元素是否有特殊性?在这方面 CSS2 有些自相矛盾,不过 CSS2.1很清楚地指出,伪元素有特殊性,百且特殊性为 0, 0, 0, 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; } /* specifity = 0, 1, 0, 0 */
div#sidebar *[href] { color: silver } /* 0, 1, 1, 1 */

假设有以下情况,一个 em元素既与上例中的第 2条规则p em { color: purple; } /* specificity = 0, 0, 0, 2 */匹配,又与第 5 和规则匹配,这个元素将是紫红色,因为第 5 条规则的特殊性高于第 2 条规则的特殊性

下面做个练习,回顾本节前面给出的几组规则,看看它们有怎样的特殊性:

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: anvy; }  /* 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更高。

之所以会这样,是因为值是从左向右排序的。特殊性值 1, 0, 0, 0 大于以 0开头的所有特殊性值,而不论后面的数是什么 。所以 0, 1, 0, 1 比 0, 0, 1, 7 高,因为前一个值中第二位上的 1 大于第二个值中第二位上的 0。

声明和特殊性

一旦确定一个选择器的特殊性,这个值将授予其所有相关声明。考虑以下规则:

h1 { color: silver; background: black; }

由于特殊性的缘故,用户代理必须相应地处理这个规则,将其"解组"为单独的规则。因此,前面的例子将变成:

h1 { color: silver; }
h1 { background: black; }

这两个规则的特殊性都是 0, 0, 0, 1,各声明得到的特殊性值也就是 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 */

当这些规则应用到以下标记时,显示的内容将如下图

<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>

在这里插入图片描述
任何情况下,用户代理都会确定哪些规则与一个元素匹配,计算出所有相关的声明及其特殊性,确定哪些规则胜出,然后将胜出的规则应用到元素,从而得到应用样式后的结果。每个元素、选择器和声明上都必须完成这些工作。幸运的是,用户代理会自动完成所有这些工作。这个行为是层叠的一个重要部分,本章后面还将深入讨论层叠。

通配选择器特殊性

前面提到过,通配选择器对一个选择器的特殊性没有贡献。换句话说,其特殊性为 0, 0, 0, 0, 这与根本没有特殊性有区别(有关内容将在"继承"一节介绍)。因此,给定以下两条规则,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 */

相比这下,结合符则根本没有特殊性,甚至连 0 特殊性都没有。因此,它们对选择器的总特殊性没有任何影响。

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 (winner) */

第二个规则中的 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 */

内联样式特殊性

到目前为止,我们已经见过以 0开头的特殊性,所以你可能会奇怪为什么会有这些特殊性。一般地,第一个 0是为内联样式声明保留的,它比所有其他声明的特殊性都高。考虑以下规则和标记片段:

h1 { color: red; }
<h1 style="color: green;"> The Meadow Party </h1>

假设这个规则应用到h1 元素,h1 的文本还将是绿色。CSS2.1中就是如此,这是因为每个内联声明的特殊性都是 1, 0, 0, 0。

这意味着,即使有 id 属性的元素与某个规则匹配,也必须遵循内联样式声明。下面把上例修改为包括一个 id 属性:

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

由于内联声明的特殊性最高,h1 元素的文本还是绿色。

注意:为内联样式声明保留一位,这是 CSS2.1才新增的,这样做是为了反映写 CSS2.1当时的 Web 浏览器表现。在 CSS2中,内联样式声明的特殊性是 1, 0, 0 (CSS2特殊性包含 3 个值,而不是 4 个)。换句话说,它与 ID 选择器的特殊性相同,所以 ID 选择器很容易覆盖内联样式。

重要性

有时某个声明可能非常重要,超过了所有其他声明。CSS2.1称之为重要声明(原因显而易见),并允许在这些声明的结束分号之前插入!important 来标志。

p.dark { color: #333 !important; background: white; }

在此为颜色值为#333加了标志!important,而背景值 white 未加这个标志。如果你希望把两个声明都标志为重要,那么每个声明都需要它自己的!important 标志:

p.dark { color: #333 !important; background: white !important; }

必须正确地放置 !important,否则声明将无效。!important 总是放在声明的最后,即分号前面。如果一个属性的值可以包含多个关键词,如 font,这一点则尤其重要,必须将!important 标志放在声明的最后:

p.light { color: yellow; font: smaller Times, serif !important; }

如果!important 放在 font 声明的任何其他位置,整个声明都将无效,相应地不会应用其任何样式。

标志为!important 的声明并没有特殊的特殊性值,不过要与非重要声明分开考虑。实际上,所有!important 声明会分组在一起,重要声明的特殊性冲突会在重要声明内部解决,而不会与非重要声明相混。类似地,我们认为所有非重要声明也归为一组,使用特殊性解决冲突。如果一个重要声明和一个非重要声明冲突,胜出的总是重要声明。以下展示了以下规则和标记片段的结果:

h1 { font-style: italic; color: gray !important; }
.title { color: black; background: silver; }
* { background: black !important; }
<h1 class="title"> NightWing</h1>

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_36210698/article/details/88407972