工具
指南

CSS 选择器优先级计算器

参考手册

计算任意 CSS 选择器的优先级三元组 (A, B, C)——ID、类、属性、伪类与元素——多选择器同时对比,并拆解每段的贡献。支持 :is()、:not()、:where()。

100% 客户端 无后端
ID 选择器 (A) 类、属性与伪类 (B) 元素与伪元素 (C)
选择器 优先级 (A, B, C)
贡献
输入一个或多个 CSS 选择器以计算其优先级。
本页内容

什么是 CSS 优先级(specificity)?#

当两条 CSS 规则都想给同一个元素的同一个属性赋值时,浏览器不是选写在后面的那条,而是选 优先级 更高的那条。优先级是一个三段式的分数 (A, B, C),级联(cascade)会比较它,就像比较版本号一样:

  • A —— ID 选择器(#header)。
  • B —— 类选择器(.btn)、属性选择器([type=email])和伪类(:hover:focus)。
  • C —— 类型选择器(diva)和伪元素(::before::first-line)。

先比 A,平局再依次落到 B、C。一个 ID (1,0,0) 能压过任意多个类 (0,99,99),而任意多个类又能压过任意多个类型。通配符 *、组合器(> + ~)和嵌套选择器 & 都不加分。

本页为你粘贴的任意选择器算出这个元组——包括现代的函数式伪类 :is():where():not():has(),以及 :nth-child()of S 子句——把一组选择器排好序,并标清每一小段各贡献了多少分。要回答那句最常见的 CSS 疑问——“我的规则为什么没生效?“——这是最快的办法。

怎么使用#

  1. 示例 载入一组现成的选择器,或清空后粘贴你自己的。你可以只贴一条选择器(#nav .item),也可以贴整条规则(#nav .item { color: red });工具只读 { 之前的部分。
  2. 有好几条?用逗号分隔——它们会按优先级从高到低排序,胜出者会被标出来。
  3. 右侧面板列出每条选择器及其 (A, B, C) 元组,并按颜色拆解每个加分片段(红 = ID、蓝 = 类/属性/伪类、绿 = 类型/伪元素),让你看清分数是怎么来的
  4. 右上角的彩色图例提醒你哪个圆点对应 A / B / C。
  5. 如果你的规则里含 !important,会弹出一条提示——!important 是声明级别的覆盖,它位于优先级比较之上,不在元组里。

主要特性#

  • 疑难情况也算得对。 :where() 永远贡献 (0,0,0):is() / :not() / :has() 取参数里最高的那条优先级;旧式 :before:nth-child()of S 子句都按 Selectors Level 4 规范处理。
  • 整列排序,并标注并列,几条规则谁会赢一眼可见。
  • 逐段拆解。 每一个 #id.类[属性]:伪类::伪元素、类型选择器都列出来,连带它贡献的原文。
  • 容忍整条规则。 粘贴 a:hover { text-decoration: underline } 没问题——注释会被剥掉,声明块自动忽略。
  • 100% 本地。 不发任何请求,不抓取也不执行任何样式表。

实例演示#

一个常见的调试谜题:三条规则都指向同一个链接,可颜色偏偏选错了那条。把它们一起粘进输入框:

.button:hover
:is(.card, #hero) .button
a.button

输出排好序:

名次选择器元组
1:is(.card, #hero) .button(1, 1, 0) —— 胜出
2.button:hover(0, 2, 0)
3a.button(0, 1, 1)

胜出的并不是类最多的那条。:is(.card, #hero) 继承了参数里最高的优先级——#hero 是个 ID,所以 :is() 拿到的是 (1,0,0),尽管 .card 单独只是 (0,1,0)。再加一个 .button,B 列加一,得到 (1,1,0)。A 列里那一个 ID 就压过了 .button:hover 的两个类 (0,2,0)——这正是 :is() 在生产 CSS 里容易踩坑的地方。

如果你想要同样的分组、又抬高优先级,就把 :is() 换成 :where()

:where(.card, #hero) .button   →   (0, 1, 0)

这下它和 a.button(去掉类型那部分)持平,由书写顺序决定胜负。:where() 存在的全部理由就是这个。

常见问题#

为什么一个 ID 能压过几百个类?#

优先级是从左到右逐列比较的,像版本号,而不是把所有分加在一起。(1,0,0)(0,999,999)”靠前”,是因为前者的 A 列非零、后者的 A 列为零;B、C 列压根不会被比较。这是有意设计的——ID 本就被设定为独一无二的单点。

:is():where() 有什么区别?#

它们匹配的范围一样,优先级却完全相反。:is(.a, #b) 取参数里最高的优先级(所以 #b 让它变成 (1,0,0));:where(.a, #b) 永远贡献 (0,0,0),不管参数是什么。想要低优先级、好被覆盖的默认样式就用 :where();真心想让组合选择器参与竞争才用 :is()

行内 style="…" 能压过这些吗?#

能。行内样式在正常级联里优先于任何基于选择器的规则(它处在更高的来源层级),所以不靠 !important,任何选择器元组都盖不过行内样式。这跟 (A,B,C) 分数是不同的轴,所以本工具只评估选择器。

!important 算在哪里?#

!important 是声明级别的标记,不是选择器的属性——它不改变 (A,B,C) 元组。它把整条声明挪到更高的级联来源,所以一条 !important 规则无论优先级高低都能压过普通规则。工具只会提示它出现了,但不把它计入分数。