@apply 在复杂样式场景下不可靠,因其依赖 PostCSS 静态展开,无法处理响应式前缀、嵌套变体及 dark:hover 等交叉逻辑,且在 scoped 样式或跨文件复用时易失效;推荐改用 @layer components 组合原子类或 tailwind-variants。

直接用 @apply 复用复杂样式,大概率会掉进响应式失效、伪类丢失、构建后消失的坑里——尤其当你写了 md:p-6 hover:bg-gray-100 dark:hover:bg-gray-800 这种组合时。
为什么 @apply 在复杂样式场景下不可靠
@apply 不是 CSS 原生语法,它依赖 Tailwind 的 PostCSS 插件做静态展开。问题在于:它不会自动包裹媒体查询、不会递归解析嵌套变体、也不处理 dark: 和 hover: 的交叉逻辑。
- 写
@apply md:p-6 lg:p-8→ 编译后只是两个普通声明,md:前缀被丢弃,响应式完全失效 - 写
@apply hover:bg-blue-500 dark:hover:bg-blue-900→ 后者常被静默忽略,或生成无效 CSS - 把
@apply放在 Vue 单文件组件的<style scoped>里 → JIT 引擎根本扫描不到,样式不生成 - 跨文件复用带变体的类 → 比如
.btn-primary里用了focus:ring-blue-500,但另一个文件 import 它时,focus:可能没被注入
用 @layer components + 原子类组合替代 @apply
这是 Tailwind 官方推荐、且实际工程中验证过的轻量方案:不生成新 CSS,保留所有变体能力,还能和 PurgeCSS 兼容。
- 在全局 CSS 入口(如
src/main.css)中,确保顺序为:@tailwind base→@layer components→@tailwind utilities -
@layer components块内只写语义化类名,内部不写@apply,而是直接组合原子类(支持响应式前缀和变体) - 例如:
.card { p-4 md:p-6 bg-white rounded-lg shadow-sm hover:shadow-md transition-shadow; }—— 这段 CSS 会被 JIT 正确解析并生成完整规则 - HTML 中直接用:
<div class="card">...,所有md:、hover:都生效
高频动态场景优先用 tailwind-variants
当组件需要根据 variant、size、disabled 等 prop 切换样式时,硬编码类名或 @apply 都会迅速失控。
立即学习“前端免费学习笔记(深入)”;
-
tailwind-variants是运行时逻辑层抽象,不是 CSS 层封装,它生成的是合法原子类字符串 - 示例:
const button = tv({ base: "px-4 py-2 rounded", variants: { variant: { primary: "bg-blue-600 text-white", outline: "border border-gray-300" } } }); - 调用:
button({ variant: "primary" })→ 返回"px-4 py-2 rounded bg-blue-600 text-white",完全兼容 JIT 和 PurgeCSS - 它天然支持响应式、暗色模式、条件组合,且类型安全(TypeScript 友好)
真正容易被忽略的点是:**“复用”不等于“抽成一个 CSS 类”**。Tailwind 的原子性优势恰恰在于可拆解——md:p-6 和 p-4 本就该独立存在,强行合并反而锁死定制能力。所谓“快速复用”,本质是控制抽象层级:静态结构用 @layer components,动态逻辑用 tv(),其余时候,直接写原子类反而最快。


















