UnoCSS 快是因为跳过编译:直接正则提取类名、查表注入CSS,响应仅1–2ms;Tailwind需全量AST解析,HMR常超400ms。

UnoCSS 为什么快:它根本没在“编译”
UnoCSS 的快不是“编译得快”,而是跳过了编译环节。Tailwind CSS v3 JIT 仍需通过 PostCSS 解析整个 AST,再遍历节点匹配类名、查表、生成规则;UnoCSS 默认不碰 AST,只对源码字符串做轻量正则提取(比如从 <div class="text-blue-500"> 中直接捕获 text-blue-500),匹配后查预置规则表注入 CSS。这导致两个关键差异:
- 新增一个类,UnoCSS 响应在 1–2ms 内;Tailwind 通常要重跑整条 CSS 构建链
- HMR 阶段,UnoCSS 稳定在 ~80ms;Tailwind 在复杂组件下常卡到 400ms+,尤其当 content 配置含大量 MDX 或注释时
- 构建时扫描范围可控:UnoCSS 默认只处理真正
import的模块路径;Tailwind 依赖 glob 全量扫描,I/O 开销随文件数线性增长
迁移前必须关掉的 Tailwind 行为
直接替换插件不会自动兼容,因为 UnoCSS 不继承 Tailwind 的运行时逻辑。以下配置若保留,会导致静默失效:
-
dark:变体不会自动生效——Tailwind 依赖class="dark"自动检测,UnoCSS 需手动注入dark类到<html>标签,或启用@unocss/preset-dynamic -
hover:underline这类变体默认启用,但如果你在uno.config.ts中禁用了variants插件,或设了preflight: false,它就完全不工作,且无报错提示 -
bg-gradient-to-r在 Tailwind 中需显式配置gradientColorStops才能生成;UnoCSS 默认支持,但自定义的theme.colors不会自动注入到渐变逻辑里,得手动补rules
用 @unocss/preset-wind 实现 99% 兼容迁移
这不是“换壳”,而是语义层兼容。它复刻了 Tailwind 的类名映射逻辑,但底层规则是重写的。迁移只需三步,且可渐进:
- 安装:
pnpm add -D @unocss/preset-wind @unocss/transformer-directives(后者用于支持@apply) - 配置
uno.config.ts:import { defineConfig } from 'unocss' import presetWind from '@unocss/preset-wind' export default defineConfig({ presets: [presetWind()], transformers: [ // 启用 @apply 支持(否则会忽略) import('@unocss/transformer-directives').then(m => m.default()) ], }) - 删掉
tailwind.config.js和所有 PostCSS 相关插件(如postcss、autoprefixer)——UnoCSS 自带 autoprefixer 行为,多加反而干扰
动态类名和安全白名单的实际处理
两者都支持运行时拼接,但提取机制不同,容易漏提:
立即学习“前端免费学习笔记(深入)”;
-
class={`text-${color}-500`}:UnoCSS 的@unocss/extractor-regex(默认启用)能提取字面量部分(如text-red-500),但无法推断color变量值;Tailwind 需配content.safeList或正则白名单 - 真正难的是模板字符串嵌套:
class={\`p-\${size} \${isActive ? 'bg-blue-500' : 'bg-gray-200'}\`}—— UnoCSS 仅提取静态分支,bg-blue-500和bg-gray-200都会被捕获;Tailwind 则可能全漏,除非你把整个表达式写进safeList - 建议:高频动态组合类,统一收口到
shortcuts,比如btn-primary→text-white bg-blue-500 hover:bg-blue-600,既可控又免白名单维护
最易被忽略的是缓存污染:迁移后务必清掉 .unocss-cache 和 Vite 的 .vite/deps,否则旧规则可能残留,导致 HMR 失效或样式不更新。


















