CSS 选择器优先级计算器
参考手册计算任意 CSS 选择器的优先级三元组 (A, B, C)——ID、类、属性、伪类与元素——多选择器同时对比,并拆解每段的贡献。支持 :is()、:not()、:where()。
本页内容
什么是 CSS 优先级(specificity)?#
当两条 CSS 规则都想给同一个元素的同一个属性赋值时,浏览器不是选写在后面的那条,而是选 优先级 更高的那条。优先级是一个三段式的分数 (A, B, C),级联(cascade)会比较它,就像比较版本号一样:
- A —— ID 选择器(
#header)。 - B —— 类选择器(
.btn)、属性选择器([type=email])和伪类(:hover、:focus)。 - C —— 类型选择器(
div、a)和伪元素(::before、::first-line)。
先比 A,平局再依次落到 B、C。一个 ID (1,0,0) 能压过任意多个类 (0,99,99),而任意多个类又能压过任意多个类型。通配符 *、组合器(> + ~)和嵌套选择器 & 都不加分。
本页为你粘贴的任意选择器算出这个元组——包括现代的函数式伪类 :is()、:where()、:not()、:has(),以及 :nth-child() 的 of S 子句——把一组选择器排好序,并标清每一小段各贡献了多少分。要回答那句最常见的 CSS 疑问——“我的规则为什么没生效?“——这是最快的办法。
怎么使用#
- 点 示例 载入一组现成的选择器,或清空后粘贴你自己的。你可以只贴一条选择器(
#nav .item),也可以贴整条规则(#nav .item { color: red });工具只读{之前的部分。 - 有好几条?用逗号分隔——它们会按优先级从高到低排序,胜出者会被标出来。
- 右侧面板列出每条选择器及其
(A, B, C)元组,并按颜色拆解每个加分片段(红 = ID、蓝 = 类/属性/伪类、绿 = 类型/伪元素),让你看清分数是怎么来的。 - 右上角的彩色图例提醒你哪个圆点对应 A / B / C。
- 如果你的规则里含
!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) |
| 3 | a.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 规则无论优先级高低都能压过普通规则。工具只会提示它出现了,但不把它计入分数。