Tailwind CSS 的 JIT 模式不解析手写嵌套选择器(如 .card .header h2),仅扫描 HTML 中出现的原子类;替代方案是 @layer components 定义扁平组件类 + group 实现父子联动,复杂场景应回归原生 CSS 并归入 @layer。

Tailwind CSS 不支持、也不应该用来实现复杂多层嵌套的 CSS 选择器。你写的 .card .header h2 或 .modal .overlay .spinner 这类规则,在构建时会被 JIT 引擎完全忽略——它不是“没生效”,而是压根没被识别为 Tailwind 代码。
为什么 .card .header h2 这类写法根本不会生成 CSS
Tailwind 的 JIT 模式只扫描 HTML 文件中实际出现的原子类名(如 text-xl、md:px-6),从不解析你在 styles.css 里手写的任何选择器。这意味着:
- 你在 CSS 文件里写
.card .header h2 { @apply text-xl; }→ 构建后无对应 CSS 输出 - 加了
md:前缀也无效,因为该选择器不在content配置路径中,JIT 直接跳过 - 热更新后样式消失?不是缓存问题,是 PostCSS 根本没把它当 Tailwind 规则处理
- 哪怕启用
postcss-nested,在嵌套块里用@apply也会报错:Cannot apply unknown utility class
想控制多层结构,必须用 @layer components + group
真正可维护、可响应、可调试的替代方案只有两条主线,且必须配合使用:
- 用
@layer components定义语义化组件类,每个类都扁平声明,例如:@layer components { .card-header { @apply px-6 py-4 border-b border-gray-200; } } - 用
group和group-hover实现父子联动,但注意:group必须显式加在父容器上(class="group"),不能写成hover:group;group-hover只对后代生效,无法影响兄弟或父级元素 - 三层及以上 DOM 嵌套?只能再套一层
group,但别超过两层——否则结构臃肿、调试困难;更推荐改用data-[state=expanded]配合 JS 控制 - 所有
group-hover:类必须显式加transition,否则无动画效果,这个细节极易漏掉
什么时候真需要原生嵌套选择器?那就别用 @apply
Tailwind 不是替代 CSS 的工具,而是与之共存的一层。三类场景绕不开原生选择器:
立即学习“前端免费学习笔记(深入)”;
- 基于 DOM 结构动态响应,比如
:has(> .error)判断子元素状态 - 穿透 scoped / shadow DOM(Vue 的
:deep(.child)或 React 的::part()) - 复杂伪类组合,如
input:not([type="hidden"]):focus + label
此时应直接写 CSS 规则,并归入 @layer components 或 @layer utilities,避免用 !important 硬顶——否则后续维护成本飙升。
Tailwind v4 已彻底移除嵌套 @apply 支持
如果你看到旧项目里 .card { &__title { @apply text-xl; } } 能跑,大概率是 v3.3 的 patch 或自定义插件在撑着。升级到 v4 后必崩。真正的分层控制靠的是 @layer 显式声明优先级,而不是靠嵌套语法模拟 Sass。最容易被忽略的点是:你写的每一个自定义类,只要想和 @tailwind utilities 公平对话,就必须明确归属到某一层——默认未声明层等价于 @layer base,天然被压制。


















