@apply 只能出现在顶层规则块中,不能在 @media、& 或其他嵌套上下文内使用,否则 tailwind postcss 插件无法解析;替代方案是用 @layer 顶层定义或直接在 html 中写响应式类。

@apply 不能出现在嵌套选择器内部,这是语法限制,不是配置或环境问题。 它只能写在顶层规则块(即直接跟在选择器后面的大括号内),一旦被包裹在 &、@media、@layer 或其他嵌套上下文里,PostCSS 插件就无法正确提取和展开它。
@apply 在嵌套选择器中失效的典型场景
比如你在 SCSS 或 Vue 的 <style scoped></style> 中写了这样的代码:
.card {
@media (min-width: 768px) {
&__header {
@apply text-lg font-bold; /* ❌ 这里会报 Cannot apply unknown utility class */
}
}
}
这个 @apply 看似合理,但 Tailwind 的 PostCSS 插件只扫描顶层声明块。它根本不会进入 @media 或 & 的嵌套作用域去解析 @apply —— 不是没运行,是压根不看。
- SCSS 编译器先处理嵌套,生成扁平 CSS 后才交给 PostCSS;此时
@apply已经被“卡”在非顶层位置,Tailwind 插件跳过 - Vue/Svelte 的
scoped+ 嵌套组合会让选择器变成类似.card[data-v-abc123] .card__header[data-v-abc123],而@apply依赖的是原始类名映射,上下文错位 - 即使你加了
@reference "tailwindcss",也只解决作用域隔离问题,不改变解析层级限制
替代方案:用 @layer + 顶层规则重构
想实现响应式或条件样式,别把 @apply 往里塞,改用 Tailwind 原生支持的方式:
- 把需要响应式的类直接写在 HTML 上:
<div class="text-lg font-bold md:text-xl"> <li>用 <code>@layer在顶层定义响应式规则:@layer utilities { @media (min-width: 768px) { .card-header-responsive { @apply text-xl font-bold; } } } - 在 Vue/Svelte 中,把逻辑拆到 class 绑定里:
:class="{ 'text-lg font-bold': isDesktop }" - v4 用户必须接受:
@apply只允许出现在「选择器 { … }」的最外层大括号内 - SCSS 文件里混用
@use和@apply会破坏类名注入时机,导致@apply解析失败,哪怕没嵌套 - Vite 项目若启用了
css.preprocessor: 'scss',需确认postcss.config.cjs中tailwindcss插件在 Sass 处理之后——顺序错了,@apply就被 Sass 提前吃掉了
容易忽略的兼容性细节
Tailwind v4 默认移除了对嵌套 @apply 的尝试性支持(v3.3 曾有实验性 patch,但已弃用)。如果你看到某些旧项目“似乎能跑”,大概率是用了自定义 PostCSS 插件或降级了版本。
真正卡住人的不是报错本身,而是误以为它是路径、配置或插件问题,花几小时调 content 字段或重装依赖,结果发现只是语法位置错了。











