CSS 播客 - 第 003 集:专属性
假设您使用的是以下 HTML 和 CSS:
<button class="branding">Hello, Specificity!</button>
.branding {
color: blue;
}
button {
color: red;
}
这里有两条定位到同一元素的规则。每条规则都包含一个声明,用于设置按钮的颜色:一条声明尝试将按钮设置为红色,另一条声明尝试将按钮设置为蓝色。系统会将哪个声明应用于该元素?
了解 CSS 特异性算法是了解 CSS 如何在竞争声明之间做出决策的关键。
具体性是广告系列的独特阶段之一,我们在上一单元中介绍了广告系列。
特异性评分
来源中的每个选择器规则都会获得一个得分。您可以将特定性视为总分,每个选择器类型都会为该分数赢得分数。系统会采用具体性最高的规则中的声明。
在实际项目中,需要平衡的因素是确保您预期要应用的 CSS 规则实际上确实应用了,同时通常保持较低的分数以防止复杂性。具体性应仅达到我们所需的程度,而不是力求尽可能高。将来,可能需要应用一些真正更重要的 CSS。如果您追求最高的具体性,则会使这项工作变得困难。
特异性不是小数,而是由三个组件(A
、B
和 C
)组成的三元组。
A
:类似 ID 的专属性B
:类似于类的专属性C
:元素般的特异性
它通常使用 (A,B,C)
表示法表示。例如:(1,0,2)
。替代 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)
。选择器的每个部分都会增加特定性,这会使 A
、B
或 C
的值递增,具体取决于选择器的类型。
通用选择器
通用选择器 (*
) 不会增加特异性,其值会保持为初始特异性 (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
(0,0,2)
。article.card.dark
(0,2,1)
。article:hover a[href]
(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;
}
这是因为这两个选择器具有相同的专属性。 在这种情况下,级联会回退到“显示顺序”步骤。