CSS 选择器优先级完全指南:从基础选择器到 specificity 计算

小飞兽 HTML/CSS 139 次阅读 2026-06-28

Introduction

CSS 选择器优先级(Specificity)决定了当多条规则作用于同一个元素时,哪条规则最终生效。理解优先级的计算方式(ID > 类/属性/伪类 > 标签/伪元素)、避免硬编码 !important,是写出可维护 CSS 的关键。优先级冲突是 CSS 中最常见的 bug 之一。

优先级分层(从高到低)

/* 最高:内联样式(写在 HTML style 属性里)*/
<div style="color: red;"> <!-- 最高优先级,无法被普通 CSS 覆盖 -->

/* 高:ID 选择器 */
#header { color: blue; }

/* 中:类选择器 / 属性选择器 / 伪类 */
.btn { color: green; }
input[type="text"] { color: purple; }
:hover { color: orange; }

/* 低:标签选择器 / 伪元素 */
div { color: red; }
::before { content: ''; }

/* 最低:通配符、组合符、否定伪类(不增加优先级)*/

  • { color: gray; }

.container > p { color: yellow; }
:not(.active) { color: black; } /* :not() 内部的选择器会计入优先级,但:not()本身不计 */

Specificity 计算公式

/* specificity 记作 (a, b, c) 三元组 */
/* a = ID 选择器数量 */
/* b = 类、属性、伪类数量 */
/* c = 标签、伪元素数量 */

/* 举例 */
#header .nav li a:visited { }
/* ID=1 (#header) */
/* 类/属性/伪类=2 (.nav, :visited) */
/* 标签/伪元素=2 (li, a) */
/* specificity = (1, 2, 2) */

/* 比较优先级:先比 a,再比 b,最后比 c */
(1, 0, 0) > (0, 10, 0) > (0, 0, 10)
/* ID 数量多的一定赢,不管类有多少 */

实战优先级示例

/* 示例1:下面的规则哪条生效?*/
.nav .link { color: blue; }     /* (0, 2, 0) */
.nav .link.active { color: red; } /* (0, 3, 0) ← 赢 */
/* 第二条多一个类,specificity 更高 */

/* 示例2:ID 赢类 */
#header { color: red; } /* (1, 0, 0) ← 赢 */
.nav .title { color: blue; } /* (0, 2, 0) */

/* 示例3:行内样式赢一切(除非另一条加了 !important)*/
<div style="color: red;"> /* (1, 0, 0) */
/* ID选择器无法覆盖它 */

/* 示例4:!important 最高 */
.nav { color: red !important; } /* !important 无视 specificity */

避免优先级陷阱的建议

/* 1. 不要用 ID 选择器(specificity 太高,难覆盖)*/
/* 不好 */
#header .nav .item .link { color: red; }
/* 好 */
.header__nav-item-link { color: red; }

/* 2. BEM 命名法天然避免优先级问题 */
.block__element--modifier { color: red; }

/* 3. 组件化:同一类选择器写在一起 */
.btn { /* ... */ }
.btn-primary { /* 继承 .btn,可直接覆盖 */ }
.btn-danger { /* 继承 .btn,可直接覆盖 */ }

/* 4. 当样式不生效时,先查 specificity */
.developer-toolbar { color: red !important; } /* 先用 !important 调试,再用正常方式替换 */

常见问题

    • !important 的坑:一旦用了 !important,所有其他规则都要加 !important 才能覆盖,形成恶性循环。只在万不得已时使用(如覆盖第三方插件样式)。
    • :not() 不增加 specificity:虽然括号内的选择器要计算,但 :not() 本身不计入 specificity 值。
    • 组合符不影响优先级: div > p、p + span、p ~ ul 中的 >、+、~ 都是组合符,它们本身的 specificity 为 0,只看选择器本身的权重。
    • 两条规则完全相同时:后面的规则覆盖前面的(后写优先),与优先级无关。

    延伸阅读

  • Specificity 计算器:specificity.keegan.st
  • BEM 命名规范:getbem.com