特异性

CSS 播客 - 第 003 集:专属性

假设您使用的是以下 HTML 和 CSS:

<button class="branding">Hello, Specificity!</button>
.branding {
  color: blue;
}

button {
  color: red;
}

这里有两条定位到同一元素的规则。每条规则都包含一个声明,用于设置按钮的颜色:一条声明尝试将按钮设置为红色,另一条声明尝试将按钮设置为蓝色。系统会将哪个声明应用于该元素?

了解 CSS 特异性算法是了解 CSS 如何在竞争声明之间做出决策的关键。

具体性是广告系列的独特阶段之一,我们在上一单元中介绍了广告系列

特异性评分

来源中的每个选择器规则都会获得一个得分。您可以将特定性视为总分,每个选择器类型都会为该分数赢得分数。系统会采用具体性最高的规则中的声明。

在实际项目中,需要平衡的因素是确保您预期要应用的 CSS 规则实际上确实应用了,同时通常保持较低的分数以防止复杂性。具体性应仅达到我们所需的程度,而不是力求尽可能高。将来,可能需要应用一些真正更重要的 CSS。如果您追求最高的具体性,则会使这项工作变得困难。

特异性不是小数,而是由三个组件(ABC)组成的三元组。

  • A:类似 ID 的专属性
  • B:类似于类的专属性
  • C:元素般的特异性

它通常使用 (A,B,C) 表示法表示。例如:(1,0,2)。替代 A-B-C 表示法也很常用。

显示特异性的三个组成部分 (A、B、C) 的示意图。图表中显示了每个组件及其代表的内容,以及影响它的一些选择器示例。
一张示意图,展示了各种选择器会影响特异性的哪个组成部分。

比较具体性

具体性是通过按顺序比较三个组成部分来比较的:A 值越大,具体性越高;如果两个 A 值相等,则 B 值越大,具体性越高;如果两个 B 值相等,则 C 值越大,具体性越高;如果所有值相等,则两个具体性相等。

例如,(1,0,0) 被视为比 (0,4,3) 更具体,因为 (1,0,0) 中的 A 值(即 1)大于 (0,4,3) 中的 A 值(即 0)。

选择器会影响具体性

特异性三元组中的每个部分都以 0 值开头,因此默认特异性为 (0,0,0)。选择器的每个部分都会增加特定性,这会使 ABC 的值递增,具体取决于选择器的类型。

通用选择器

通用选择器 (*) 不会增加特异性,其值会保持为初始特异性 (0,0,0)

* {
  color: red;
}

元素或伪元素选择器

元素(类型)或伪元素选择器会添加类似元素的专属性,该属性会将 C 组件按 1 递增。

以下示例的总体特异性为 (0,0,1)

类型选择器

div {
  color: red;
}

伪元素选择器

::selection {
  color: red;
}

类、伪类或属性选择器

伪类属性选择器会添加类似的专属性,该属性会将 B 组件递增 1

以下示例的特定性为 (0,1,0)

类选择器

.my-class {
  color: red;
}

伪类选择器

:hover {
  color: red;
}

属性选择器

[href='#'] {
  color: red;
}

ID 选择器

ID 选择器会添加类似 ID 的专属性,这会将 C 组件递增 1,前提是您使用的是 ID 选择器 (#myID),而不是属性选择器 ([id="myID"])。

在以下示例中,特异性为 (1,0,0)

#myID {
  color: red;
}

其他选择器

CSS 有许多选择器。其中有些特征并不能增加具体性。例如,:not() 伪类本身不会对特异性计算产生任何影响。

不过,作为参数传入的选择器会被添加到特异性计算中。

div:not(.my-class) {
  color: red;
}

此示例的特定性为 (0,1,1),因为它在 :not() 有一个类型选择器 (div) 和一个类。

检查您的理解情况

测试您对特异性评分的了解

a[href="#"] 的具体含义是什么?

(0,0,1)
a 的价值为 (0,0,1),但 [href="#"] 的价值为 (0,1,0)
(0,1,0)
请重试!a 的价值为 (0,0,1),但 [href="#"] 的价值为 (0,1,0)
(0,1,1)
a 的值为 (0,0,1)[href="#"] 的值为 (0,1,1),因此总特异性为 (0,1,1)

不会影响特异性的因素

关于影响特定性的以下因素,存在一些常见的误解。

内嵌样式属性

直接应用于元素的 style 属性的 CSS 不会影响特异性,因为它是级联中在特异性之前评估的另一个步骤。

<div style="color: red"></div>

如需从样式表中替换此声明,您必须在级联的较早步骤中让声明胜出。

例如,您可以向其添加 !important,使其成为受信任的 !important 来源的一部分。

!important 声明

CSS 声明末尾的 !important 不会影响特定性,但会将声明放入其他来源,即由作者提供的 !important

在以下示例中,.my-class 的特定性与 !important 声明的胜出无关。

.my-class {
  color: red !important;
  color: white;
}

如果两个声明均为 !important,则具体性再次发挥作用,因为级联中的来源步骤尚无法确定胜出者。

.branding {
  color: blue !important;
}

button {
  color: red !important;
}

在上下文中的具体性

使用复杂或复合选择器时,该选择器的每个部分都会增加特异性。请参考以下 HTML 示例:

<a class="my-class another-class" href="#">A link</a>

此链接包含两个类。 以下 CSS 中的规则具有 (0,0,1) 的特异性

a {
  color: red;
}

如果您在选择器中引用其中一个类,则该选择器现在的特异性为 (0,1,1)

a.my-class {
  color: green;
}

将另一个类添加到选择器,现在它的特异性为 (0,2,1)

a.my-class.another-class {
  color: rebeccapurple;
}

href 属性添加到选择器,现在它的特定性为 (0,3,1)

a.my-class.another-class[href] {
  color: goldenrod;
}

最后,为所有这些添加 :hover 伪类,选择器最终的特异性为 (0,4,1)

a.my-class.another-class[href]:hover {
  color: lightgrey;
}

检查您的理解情况

测试您对特异性评分的了解

以下哪个选择器的特定性为 (0,2,1)

article > section
元素会添加元素般的特异性(`C` 组件)。选择器中有 2 个元素,因此其特异性为 (0,0,2)
article.card.dark
元素会添加元素类似的特定性(`C` 组件),而类会添加类类似的特定性(`B` 组件)。由于包含 2 个类和 1 个元素,因此此选择器的专属性为 (0,2,1)
article:hover a[href]
元素会添加类似元素的特定性(`C` 组件),伪类和属性会添加类似类的特定性(`B` 组件)。其中包含 2 个元素选择器(值为 2 × (0,0,1))、1 个属性选择器(值为 (0,0,1))和 1 个类选择器(值为 (0,0,1))。因此,此选择器的总专属性为 (0,2,2)

实用地提高具体性

假设您有如下 CSS:

.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

使用如下所示的 HTML:

<button class="my-button" onclick="alert('hello')">Click me</button>

该按钮的背景为灰色,因为第二个选择器的特定性为 (0,1,1)。这是因为它有一个类型选择器 (button),即 (0,0,1),以及一个属性选择器 ([onclick]),即 (0,1,0)

上一个规则 .my-button 等于 (0,1,0),因为它只有一个类选择器,而该选择器的特定性低于 (0,1,1)

如果您想提高此规则的优先级,可以重复类选择器,如下所示:

.my-button.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

现在,该按钮将具有蓝色背景,因为新选择器的特定性为 (0,2,0)

如果在具体性方面不相上下,则回退到级联中的下一步

我们先继续使用按钮示例,将 CSS 切换为以下代码:

.my-button {
  background: blue;
}

[onclick] {
  background: grey;
}

该按钮的背景为灰色,因为这两个选择器的特定性相同,均为 (0,1,0)

如果您按来源顺序切换规则,该按钮将变为蓝色。

[onclick] {
  background: grey;
}

.my-button {
  background: blue;
}

这是因为这两个选择器具有相同的专属性。 在这种情况下,级联会回退到“显示顺序”步骤

资源