CSS 选择器优先级

学习

CSS 选择器优先级

2026-02-23/0/ 编辑


CSS 选择器优先级

1. 概念

当多个 CSS 规则集同时作用于同一个 HTML 标签时:

  • 不同属性会叠加
  • 相同属性会发生覆盖

在发生覆盖时:

  • 如果多个选择器优先级一样,则以写在后面的选择器中的属性为主
  • 如果选择器优先级不一样,则以选择器优先级最高那个选择器中的属性值为主

2. 单个选择器类型的权重

2.1 权重值系统

不同类型的选择器有不同的分数值,分数值越高,选择器的权重越高。

选择器的类型实例选择器权重等级
!importantdiv{ color:red!important; }无穷大特级
行内样式style='color:red;'1000第一等级
ID 选择器#id0100第二等级
class、伪类、属性选择器.box, :hover, [type='text']0010第三等级
标签选择器、伪元素选择器div, ::after, ::before0001第四等级
通配符、子选择器、相邻选择器等*, >, +, ~0000第五等级
继承的样式-0000-

提示:

  • 通配符 * 权重实际是要大于继承的样式的
  • 权重值只是相对概念,不能相加后进位

2.2 基础选择器优先级

基础选择器优先级从高到低:

  1. ID 选择器 > Class 选择器 > 标签选择器 > 通配符选择器

3. 复杂选择器优先级计算

3.1 计算规则

优先级就是分配给指定的 CSS 声明的一个权重

选择器的优先级是由选择器中的每一种选择器类型的数值(权值)相加的最终结果来决定。(数值越大,代表选择器的优先级越高)

权重计算表

选择器千位百位十位个位优先级
行内样式10001000
div p00020002
#box div p01020102
.box .item h300210021
.box:hover p00210021

3.2 案例分析

案例 1: 相同优先级

问题: 鼠标放在 p 标签上,文字会变成红色吗?

/* 优先级 0011 */
p:hover {
  color: red;
}

/* 优先级 0011 */
.box p {
  color: blue;
}
<body>
  <div class="box">
    <p>文本内容</p>
  </div>
</body>

答案: 鼠标滑动到 p 上面,文字并不会变成红色

原因: 两选择器优先级相同,都是 0011,则以写在后面的为主,相同属性发生覆盖。则最终效果为 blue 蓝色,鼠标滑上去文字并不会变色。

案例 2: 不同优先级

问题: 以下案例中的 p 标签的最终显示效果怎样的?

/* 优先级:100 */
#title {
  color: red;       /* 生效 */
}

/* 优先级:20 */
.box .title {
  color: blue;      /* 不生效,以#title为主 */
}

/* 优先级:10 */
.title {
  font-size: 16px;  /* 生效 */
}

/* 优先级:2 */
div p {
  font-size: 40px;  /* 不生效,以.title中为主 */
}
<body>
  <div class="box">
    <p id="title" class="title">p中内容</p>
  </div>
</body>

最终效果:

  • color: red (ID 选择器优先级最高)
  • font-size: 16px (.title 优先级高于 div p)

案例 3: 多层嵌套优先级

问题: 以下案例中,p 标签中的文字最终是以什么颜色显示?

/* 优先级 0201 */
#box1 #box2 p {
  color: red;
}

/* 优先级 0212 - 三个中优先级最高,则以他为主 */
#box1 div.box2 #box3 p {
  color: green;
}

/* 优先级 0031 */
.box1 .box2 .box3 p {
  color: blue;
}
<body>
  <div class="box1" id="box1">
    <div class="box2" id="box2">
      <div class="box3" id="box3">
        <p>我是一个段落标签</p>
      </div>
    </div>
  </div>
</body>

最终效果: 绿色,因为 #box1 div.box2 #box3 p 优先级最高(0212)


4. 优先级计算注意事项

4.1 不允许进位

在进行选择器权重计算时不允许进位

例如,20 个类选择器仅仅意味着 20 个十位,而不能视为两个百位,也就是说,无论多少个类选择器的权重叠加,都不会超过一个 ID 选择器

#box {
  /* 优先级 0100 */
}

/* 以下 20 个类选择器的权重都是要比 #box 选择器的权重要低 */
.item.item2......item20 {
  /* 优先级 0020,仍然低于 ID 选择器 */
}

4.2 优先级计算技巧

在比较选择器优先级时,如果都要计算出每个选择器优先级权重值,再来决定优先级高低,那肯定相当麻烦。

推荐一个又快又好的计算优先级的方法:

先比较高位,再比较低位

先比较 ID 选择器,再比较 class、伪类、属性选择器选择器,再比较 标签、伪元素选择器选择器

  1. 如果 ID 选择器个数不一样,则以 ID 选择器个数多的为主

    • 如果个数一样,则再比较 class、伪类、属性选择器加起的个数
  2. 如果 class 选择器个数不一样,则以 class 选择器多的为主

    • 如果个数一样,则往后再比较标签、伪元素选择器加起来的个数
    • 原理和 ID 选择器比较一样,依此类推

示例 1: ID 选择器比较

/* 先比较两者中的 ID 选择器个数 */
/* 第一个选择器中 ID 个数为 1,第二个为 0,则以 #box 中的样式为主 */
#box {
  /* ID 个数: 1 */
}

.item p {
  /* ID 个数: 0 */
}

结果: #box 优先级更高

示例 2: 相同 ID,比较标签

/* 两者中 ID 个数一样,则比较 class 类 */
/* 类也一样为 0,则比较标签 */
/* 标签个数也一样,则两者优先级一样 */
/* 优先级一样,谁在后面听谁的 */

#box p {
  /* ID: 1, Class: 0, 标签: 1 */
}

div p#title {
  /* ID: 1, Class: 0, 标签: 2 */
}

结果: 第二个选择器优先级更高(标签更多)

示例 3: 比较 class 选择器

/* ID 个数都为 0,则比较 class 类 */
/* 第一个有 2 个 class,第二个只有一个 class */
/* 所以第一个选择器优先级要高,以第一个为主 */

.box .item p {
  /* ID: 0, Class: 2, 标签: 1 */
}

.box div p {
  /* ID: 0, Class: 1, 标签: 2 */
}

结果: 第一个选择器优先级更高(class 更多)


5. !important 提升权重

5.1 !important 的作用

当在一个样式声明中使用一个 !important 规则时,此声明将覆盖任何其他声明,包括行内样式

虽然,从技术上讲,!important 与优先级无关,但它与最终的结果直接相关。

示例

div {
  color: red !important;
}

#box {
  color: orange;
}
<body>
  <div style="color: blue">文本内容</div>
</body>

结果: 红色,!important 覆盖了行内样式

注意: 只要 CSS 声明属性值后面带 !important,就一定以他为主。

5.2 慎用 !important

不过我们要慎用 !important,因为这会带来样式的冲突。后面某个地方,需要重写这个样式时,会发现根本无效。一般你在利用第三方组件或 CSS 框架时,如果不能重写样式,那将会失去很多色彩。

某些情况下是可以用的:

  • 自定义字体时,font-family 属性后面可以加 !important 关键字
  • 覆盖第三方库的样式
  • 紧急修复(临时方案)

6. CSS 选择器冲突解决流程

通过右击审查元素,找到有哪些选择器在控制当前标签元素的样式,然后按以下步骤来分析:

6.1 冲突解决步骤

  1. 是否找不到自己写的 CSS 选择器

    • 如果是,则肯定是选择器单词写错造成
  2. 看元素要生效的样式是否被其它样式覆盖了

    • 属性后面书写了 important 关键词

      • 如果是,去掉 important
    • 元素是否有添加行内样式,被行内样式覆盖了

      • 如果是,则将行内样式改为内联或外链样式
    • 选择器优先级问题造成的覆盖

      • 如果是优先级,则提升优先级
    • 书写顺序问题造成的覆盖

      • 如果是书写顺序,则调整书写顺序

6.2 常见冲突场景

场景 1: 样式不生效

.box {
  color: red;
}

.box {
  color: blue;  /* 后写的覆盖先写的 */
}

结果: 蓝色

场景 2: 优先级不足

p {
  color: red;
}

.content p {
  color: blue;
}

结果: 蓝色(优先级 11 > 1)

场景 3: 悬停效果不生效

/* 优先级 12 */
li a:hover {
  color: yellow;
}

/* 优先级 12 */
.list li a {
  color: orange;
}

结果: 橙色,鼠标滑上去文字不会变成黄色

解决: 提高悬停选择器的优先级

.list li a:hover {
  color: yellow;
}

7. 实战练习

练习 1: 计算优先级

计算以下选择器的优先级:

/* 选择器 1 */
body div p { }

/* 选择器 2 */
.container .item p { }

/* 选择器 3 */
#main .content p { }

/* 选择器 4 */
div p:hover { }

答案:

  • 选择器 1: 0002 (2 个标签)
  • 选择器 2: 0020 (2 个类 + 1 个标签)
  • 选择器 3: 0110 (1 个 ID + 1 个类 + 1 个标签)
  • 选择器 4: 0011 (1 个类 + 2 个标签)

练习 2: 最终颜色

以下 span 中文字的颜色是?

.col {
  color: red;
}

div p span {
  color: blue;
}
<body>
  <div>
    <p><span>span标签的文字颜色</span></p>
  </div>
</body>

答案: 蓝色,因为 .col 并没有作用于 span 标签

练习 3: 悬停效果

鼠标滑动到 a 标签,a 标签中文字能不能变成黄色?

/* 12 */
li a:hover {
  color: yellow;
}

/* 12 */
.list li a {
  color: orange;
}
<body>
  <ul class="list">
    <li><a href="">艾编程</a></li>
  </ul>
</body>

答案: 不能,li a:hover.list li a 的优先级一样,以写在后面的为主,则鼠标滑上去,文字不会变成黄色

练习 4: 后代与子代

以下 li 中和 a 中的文字颜色分别?

/* 2 */
ul li {
  color: red;
}

/* 2 */
ul > li {
  color: orange;
}
<body>
  <ul class="list">
    <li>点击进入<a href="">艾编程</a></li>
  </ul>
</body>

答案: 橘黄色,ul liul > li 的优先级是一样的,以写在后面的为主


8. 最佳实践

8.1 避免过度嵌套

/* ❌ 不推荐: 过度嵌套,难以覆盖 */
.container .sidebar .widget .title {
  color: red;
}

/* ✅ 推荐: 使用简洁的类选择器 */
.widget-title {
  color: red;
}

8.2 使用类选择器为主

/* ❌ 不推荐: 过度使用 ID 选择器 */
#header {
  color: blue;
}

#header .nav {
  color: white;
}

/* ✅ 推荐: 使用类选择器 */
.header {
  color: blue;
}

.header .nav {
  color: white;
}

8.3 保持选择器简洁

/* ❌ 不推荐: 过于复杂的选择器 */
div ul li a span.highlight {
  color: red;
}

/* ✅ 推荐: 简洁的选择器 */
.highlight {
  color: red;
}

8.4 利用 BEM 命名法

/* 块 */
.card {
  background: white;
}

/* 元素 */
.card__title {
  font-size: 1.5em;
}

/* 修饰符 */
.card--primary {
  border: 2px solid #007bff;
}

9. 总结

CSS 选择器优先级关键要点:

  1. 权重系统:

    • !important: 无穷大
    • 行内样式: 1000
    • ID 选择器: 100
    • class/伪类/属性选择器: 10
    • 标签/伪元素选择器: 1
    • 通配符/关系选择器: 0
    • 继承的样式: 0
  2. 计算方法:

    • 各选择器类型权重相加
    • 不允许进位
    • 先比高位(ID),再比低位
  3. 计算技巧:

    • 先比较 ID 选择器个数
    • 再比较 class 选择器个数
    • 最后比较标签选择器个数
  4. !important:

    • 最高优先级
    • 慎用,避免样式冲突
  5. 冲突解决:

    • 检查选择器是否正确
    • 计算优先级
    • 调整书写顺序
    • 提升优先级或使用 !important
  6. 最佳实践:

    • 避免过度嵌套
    • 使用类选择器为主
    • 保持选择器简洁
    • 利用 BEM 命名法