0%

CSS选择器的优先级和权重计算规则

在编写 CSS 时,经常遇到多个规则作用于同一个元素的情况,最终哪个规则生效由选择器的优先级决定。

什么是选择器优先级?

当多个 CSS 规则同时匹配一个元素时,浏览器需要根据一定的规则来决定哪个样式生效。这个规则就是优先级(Specificity)。优先级是一个由四部分组成的权重体系,权重高的规则胜出。如果权重相同,则后定义的规则覆盖先定义的规则(层叠顺序)。

优先级权重计算规则

CSS 选择器的优先级可以表示为四部分:(内联样式,ID 选择器,类/伪类/属性选择器,元素/伪元素选择器)。通常用 (a, b, c, d) 来表示:

  • a:内联样式(inline style),即在 HTML 元素的 style 属性中定义的样式。它的优先级最高,记作 1,0,0,0。
  • b:ID 选择器的数量,例如 #header,记作 0,1,0,0。
  • c:类选择器(如 .box)、伪类选择器(如 :hover)、属性选择器(如 [type=“text”])的数量,记作 0,0,1,0。
  • d:元素选择器(如 div)、伪元素选择器(如 ::before)的数量,记作 0,0,0,1。
    此外:
  • 通配符选择器 *、组合器(+、>、~、空格)和否定伪类 :not() 本身对优先级没有贡献,但 :not() 内部的选择器会正常计算权重。
  • !important 规则会覆盖任何普通优先级声明,但同属 !important 时仍按优先级比较。

计算示例

示例 1:简单选择器

1
2
3
4
5
6
7
8
/* 权重 (0,0,0,1) */
div { color: red; }

/* 权重 (0,0,1,0) */
.my-class { color: blue; }

/* 权重 (0,1,0,0) */
#my-id { color: green; }

对于 <div id="my-id" class="my-class"> 元素,三个规则都匹配,优先级最高的 #my-id 生效,文字为绿色。

示例 2:组合选择器

1
2
3
4
5
6
7
8
/* 权重 (0,0,1,1) */
div.my-class { color: red; }

/* 权重 (0,1,0,1) */
div#my-id { color: blue; }

/* 权重 (0,1,1,0) */
#my-id.my-class { color: green; }

对于 <div id="my-id" class="my-class">,第三个规则权重最高(一个 ID + 一个类),生效为绿色。

示例 3:复杂选择器

1
2
3
4
/* 权重 (0,1,2,1) */
#nav .list > li:hover a::before {
color: red;
}

计算过程:

  • ID 选择器:#nav → 1 个 → b=1
  • 类/伪类/属性:.list 和 :hover → 2 个 → c=2
  • 元素/伪元素:li、a、::before → 3 个 → d=3
  • 内联样式:0 → a=0

最终权重 (0,1,2,3)。

示例 4:内联样式

1
2
3
4
5
<div id="box" class="box" style="color: black;">文本</div>

#box { color: red; } /* (0,1,0,0) */
.box { color: blue; } /* (0,0,1,0) */
div { color: green; } /* (0,0,0,1) */

内联样式权重为 (1,0,0,0),最高,最终文字为黑色。

!important 规则

  • !important 写在属性值后面,表示该声明具有最高优先级。
  • 它会覆盖任何普通声明(包括内联样式),但如果有多个 !important 规则,则仍然按常规优先级比较。
1
2
p { color: red !important; }      /* 权重极高 */
#text { color: blue; } /* 普通优先级 */

对于 <p id="text">,虽然 ID 选择器权重更高,但 !important 使红色生效。

1
2
p#text { color: red !important; }   /* (0,1,0,1) + !important */
p { color: blue !important; } /* (0,0,0,1) + !important */

两者都是 !important,比较权重:第一个有一个 ID,第二个没有,所以第一个生效。

特殊情况的处理

通配符和组合器

通配符 * 以及组合器(+、>、~、空格)本身不计入权重,但组合器连接的选择器分别计算。

1
2
* { color: black; }           /* (0,0,0,0) */
div * p { color: red; } /* (0,0,0,2) (两个元素选择器) */

:not() 伪类

:not() 本身不计入权重,但其内部的选择器正常计算。

1
div:not(.hidden) { color: red; }   /* (0,0,1,1)(一个元素 + 一个类) */

继承的样式

继承的样式没有优先级,任何直接作用于元素的规则都会覆盖继承的值。

优先级比较的常见误区

  • 误区一:认为类选择器比元素选择器权重高,这是正确的,但需要精确计算数量。
  • 误区二:认为 !important 可以无视任何规则,但实际上多个 !important 仍要比较权重。
  • 误区三:认为行内样式权重无限大,但实际上它只是 (1,0,0,0),可以被 !important 覆盖。
  • 误区四:认为权重可以进位,比如 10 个类选择器可以超过 1 个 ID 选择器。权重不进位,无论多少个类选择器,都无法超过一个 ID 选择器。例如 (0,0,11,0) 仍然小于 (0,1,0,0)。

总结

CSS 优先级规则可以概括为以下层级(从高到低):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌───────────────────────────┐
│ !important 规则 │ 相同 !important 再比较内联等
└───────────┬───────────────┘
┌───────────▼───────────────┐
│ 内联样式(style 属性) │
└───────────┬───────────────┘
┌───────────▼───────────────┐
│ ID 选择器数量 │
└───────────┬───────────────┘
┌───────────▼───────────────┐
│ 类、伪类、属性选择器数量 │
└───────────┬───────────────┘
┌───────────▼───────────────┐
│ 元素、伪元素选择器数 │
└───────────┬───────────────┘
┌───────────▼───────────────┐
│ 通配符、组合器(无贡献) │
└───────────┬───────────────┘
┌───────────▼───────────────┐
│ 继承样式(最低) │
└───────────────────────────┘

权重计算口诀:内联最高,ID 次之,类第三,元素最后。!important 权倾天下,但内斗仍按上述规则。