多个类连写是交集选择器,特异性机械累加(如.a.b为0,0,2,0),仅当元素同时拥有这些class才匹配;误加空格、DOM结构不满足、构建工具改名或动态绑定漏空格均导致失效。

多个类连写确实能提高特异性,但只加1点权重
写 .classA.classB 确实比单独写 .classA 多1个类选择器计数,特异性从 0,0,1,0 变成 0,0,2,0。它不是“越写越多越强”,只是机械累加——.a.b.c 是 0,0,3,0,和 .a.b 之间差的只是那1点 c 值。
这个提升非常有限:它压不过一个 ID(#id 是 0,1,0,0),也压不过带属性的同类选择器(.btn[disabled] 同样是 0,0,2,0,但语义更明确)。
- 必须作用于同一元素:
<div class="classA classB"> 才匹配;<code><div class="classA"> <p class="classB"> 完全不生效 </p> <li>HTML 中 class 属性值必须用空格分隔,不能写成 <code>class="classAclassB"或class="classA,classB" - 浏览器对重复类名去重,
.btn.btn和.btn权重一样(c=1),不算两次 - Vue/React 动态绑定时,漏掉空格会拼成
class="cardtitle",变成一个新类名 - CSS Modules 下,
.card.title是无效写法,实际 class 名类似_abc123 _def456,必须用styles.card + ' ' + styles.title拼接 - Tailwind 开了
prefix: 'tw-',但模板里还写class="card title",那.card.title根本不存在 - 用元素限定:
button.primary(0,0,1,1)比.primary(0,0,1,0)高,且不破坏复用性 - 用属性选择器强化:
.btn[disabled]、.link[href^="https"],语义清晰,权重自然上升 - 加一层有意义的父容器限定:
.modal.is-open .btn,比盲目加类更易理解上下文 - 必要时用
!important,但仅限覆盖第三方库内联样式或主题切换等不可绕过场景 - Vite + CSS Modules 默认启用局部作用域,
.user-card.active在源码里有效,但编译后变成.abc123_def456.ghi789,你手写的交集选择器根本找不到目标 - PostCSS 插件如
cssnano开启reduceIdents,可能把重复类名当成冗余删掉 - Less/Sass 中误用
&:写成.user-card { &.active { ... } }编译后是.user-card.active,没问题;但若父选择器本身没正确应用(比如 HTML 漏了user-card类),整个规则就失效
.classA.classB 不生效?先确认是否真匹配上了
最常见问题是误以为结构嵌套就能触发交集。比如你写了 .card.title,但 DOM 是 <div class="card">
<h2 class="title">——这根本不会命中,因为两个类不在同一个元素上。</h2>
<p>打开 DevTools,右键目标元素 → “检查”,直接看 <code>class 属性里是否**同时存在且拼写完全一致**(大小写敏感、无多余空格、无框架自动添加前缀)。
比堆砌类名更可靠、更可维护的提权方式
靠 .a.a.a 或 .a.b.c.d.e 强行提权,往往说明样式组织已失控。真正该优先尝试的是:
注意::where(.a.b) 会把权重重置为 0,0,1,0,里面再写多少类都白搭。
构建工具和框架可能悄悄破坏你的交集选择器
你以为写的 .user-card.active,上线后失效,大概率不是语法错,而是构建链路改了输出结果。
例如:
真正难调试的,从来不是“怎么写”,而是“写完之后,它到底有没有出现在最终生成的 CSS 文件里、对应到哪个 class 名上”。每次怀疑交集失效,第一反应不该是改选择器,而是查 network 面板里加载的 CSS 内容,或者用 document.querySelector('.user-card.active') 直接验证是否存在匹配节点。











