计算选择器的特异性
每个 CSS Selector 都有自己的特定值。序列中的每个选择器都会增加序列的整体特异性。选择者属于三个不同的特异性组之一: A , B 和 c 。当多个选择器序列选择给定元素时,浏览器使用具有最高整体特异性的序列应用的样式。
A 组是最具体的,其次是 B 组,最后是 C 组。
通用选择器(*
)和组合器(如 >
和~
)没有特异性。
示例 1:各种选择器序列的特异性
#foo #baz {} /* a=2, b=0, c=0 */
#foo.bar {} /* a=1, b=1, c=0 */
#foo {} /* a=1, b=0, c=0 */
.bar:hover {} /* a=0, b=2, c=0 */
div.bar {} /* a=0, b=1, c=1 */
:hover {} /* a=0, b=1, c=0 */
[title] {} /* a=0, b=1, c=0 */
.bar {} /* a=0, b=1, c=0 */
div ul + li {} /* a=0, b=0, c=3 */
p::after {} /* a=0, b=0, c=2 */
*::before {} /* a=0, b=0, c=1 */
::before {} /* a=0, b=0, c=1 */
div {} /* a=0, b=0, c=1 */
* {} /* a=0, b=0, c=0 */
示例 2:浏览器如何使用特异性
想象一下以下的 CSS 实现:
#foo {
color: blue;
}
.bar {
color: red;
background: black;
}
这里我们有一个 ID 选择器,它将 color
声明为蓝色,一个类选择器将 color
声明为红色,将 background
声明为黑色。
两个声明将选择 ID 为 #foo
和 .bar
类的元素。ID 选择器具有 A 组特异性,类选择器具有 B 组特异性。ID 选择器超过任意数量的类选择器。因此,来自 #foo
选择器的 color:blue;
和来自 .bar
选择器的 background:black;
将应用于该元素。ID 选择器的更高特异性将导致浏览器忽略 .bar
选择器的 color
声明。
现在想象一下不同的 CSS 实现:
.bar {
color: red;
background: black;
}
.baz {
background: white;
}
这里我们有两个类选择器; 其中一个宣称 color
为红色,background
为黑色,另一个宣称 background
为白色。
具有 .bar
和 .baz
类的元素将受到这两个声明的影响,但是我们现在遇到的问题是 .bar
和 .baz
具有相同的 B 组特异性。CSS 的级联性质为我们解决了这个问题:由于 .baz
是在 .bar
之后定义的,我们的元素最终得到了来自 .bar
的红色 color
,但是来自 .baz
的白色 background
。
例 3:如何操作特异性
可以操作上面示例 2 中的最后一个片段,以确保使用 .bar
类选择器的 color
声明而不是 .baz
类选择器的声明。
.bar {} /* a=0, b=1, c=0 */
.baz {} /* a=0, b=1, c=0 */
实现这一目标的最常见方法是找出可以应用于 .bar
选择器序列的其他选择器。例如,如果 .bar
类仅应用于 span
元素,我们可以将 .bar
选择器修改为 span.bar
。这将给它一个新的 C 组特异性,它将覆盖 .baz
选择器的缺乏:
span.bar {} /* a=0, b=1, c=1 */
.baz {} /* a=0, b=1, c=0 */
然而,可能并不总是能够找到在使用 .bar
类的任何元素之间共享的另一个公共选择器。因此,CSS 允许我们复制选择器以增加特异性。我们可以使用 .bar.bar
代替 .bar
(参见选择器的语法,W3C 推荐标准 )。这仍然选择具有 .bar
类的任何元素,但现在具有组 B 特异性的两倍 :
.bar.bar {} /* a=0, b=2, c=0 */
.baz {} /* a=0, b=1, c=0 */
!important
和内联样式声明
样式声明中的 !important
标志和 HTML style
属性声明的样式被认为具有比任何选择器更高的特异性。如果存在这些,它们影响的样式声明将否决其他声明,无论它们的特殊性如何。也就是说,除非你有多个声明包含适用于同一元素的同一属性的 !important
标志。然后,正常的特异性规则将适用于那些相互引用的属性。
因为它们完全覆盖了特异性,所以在大多数使用案例中都不赞成使用 !important
。人们应该尽可能少地使用它。为了长期保持 CSS 代码的有效性和可维护性,增加周围选择器的特异性几乎总是比使用 !important
更好。
!important
并不令人讨厌的罕见例外之一是在实现通用助手类时,如 .hidden
或 .background-yellow
类,它们应始终在任何遇到的地方覆盖一个或多个属性。即便如此,你还需要知道自己在做什么。在编写可维护的 CSS 时,你想要的最后一件事就是在整个 CSS 中使用 !important
标志。
最后一点
关于 CSS 特异性的一个常见误解是 A , B 和 C 组值应相互组合(a=1, b=5, c=1
=> 151)。这是不是这种情况。如果是这种情况,拥有 20 个 B 组或 C 组选择器就足以分别覆盖单个 A 组或 B 组选择器。这三组应被视为具体的个体水平。特异性不能用单个值表示。
创建 CSS 样式表时,应尽可能保持最低的特异性。如果你需要将特异性提高一点来覆盖另一种方法,那就让它更高但尽可能低,以使其更高。你不应该有这样的选择器:
body.page header.container nav div#main-nav li a {}
这使得未来的变化更加困难并污染了 css 页面。
你可以计算出你选择的特殊性这里