计算选择器的特异性
每个 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 页面。
你可以计算出你选择的特殊性这里