交集选择器是多个class名连写(无空格),表示同时拥有这些class的元素,如.a.b匹配;空格分隔为后代选择器,.a .b匹配.a内部任意层级的.b;连写无顺序要求且特异性累加;主要用于复用语义类,避免命名爆炸。

多个class名连写就是交集选择器,不是空格分隔
很多人写 .btn.primary 却加了空格变成 .btn .primary,结果样式完全不生效——这是最常踩的坑。CSS里连续写两个类名(中间没空格)表示“同时拥有这两个class”的元素,是逻辑与关系。
-
.a.b匹配的是<div class="a b">,不是 <code><div class="a"><span class="b"> <li>空格是后代选择器:<code>.a .b会匹配.a内部任意层级的.b - 连写没有顺序要求:
.primary.btn和.btn.primary完全等价 - 浏览器解析时,连写选择器的特异性(specificity)等于各class特异性之和,比如
.a.b.c是 0-3-0 - 适合状态类(
.is-active、.has-error)与容器类(.form、.menu)组合 - 比单class更易维护:改状态逻辑只需切换class名,CSS规则不动
- 注意BEM中
.btn--large这种双横线是修饰符,不是交集;它和.btn是独立class,靠命名约定关联 - React/Vue里动态拼接class时容易漏掉空格:
className={`list-item ${isActive ? 'selected' : ''}`}如果没处理空字符串,可能生成class="list-itemselected",变成一个新class名 - CSS-in-JS(如Emotion)里写
css({ '&.active': { ... } })是合法的,但&.active依赖父选择器存在,不能单独用 - 工具链(如PostCSS)若开启class压缩或scoped,可能重命名导致交集失效,需检查输出后的class是否仍匹配
- 如果还要兼容IE8,必须用单class替代,或用JS补丁(如ie8.js)
- Vue的
:class或React的clsx库能安全处理条件class拼接,推荐直接用 - 不要为了“提高特异性”硬凑三个class连写:
.header.nav.main看似更具体,实则耦合HTML结构,一改就崩
为什么用交集选择器而不是单个更长的class名
交集选择器本质是复用已有语义类,避免爆炸式命名。比如你已有 .card 和 .is-hovered,组合成 .card.is-hovered 就能精准控制悬停态下的卡片样式,不用另起一个 .card-hovered。
交集选择器在实际项目中的典型误用
常见错误不是语法写错,而是对HTML结构预期偏差。比如以为 .list-item.selected 能匹配到 <li class="list-item"><span class="selected"></span></li>,其实不能——.selected 必须和 .list-item 在同一个元素上。
交集选择器的性能和兼容性底线
现代浏览器对 .a.b.c 这种选择器解析毫无压力,无需担心性能。真正要注意的是IE8及更早版本——它不支持多个class连写,只认第一个(即 .a.b 在IE8里等价于 .a)。
交集选择器的边界很清晰:它只关心“这个元素有没有那几个class”,不关心它在哪、嵌套多深、是不是动态加的——只要DOM上真实存在,它就生效。最容易被忽略的,其实是上线后被JS脚本覆盖或清空class的操作,而不是CSS本身写错了。











