UnoCSS 相比 Tailwind CSS 通常快 2.5–5.2 倍,实际性能差异取决于是否启用 @apply 等指令、所使用的构建工具链,以及内容扫描范围;在纯原子类提取场景下优势最明显,启用 transformer 后差距会缩小,但整体仍然十分突出。

UnoCSS 比 Tailwind CSS 快 2.5 至 5.2 倍,具体差距会受到多种因素影响,例如是否启用了@apply、@screen 等 CSS 指令,以及构建工具链配置和内容扫描范围的大小。在纯原子类提取的使用场景中,两者的性能差异最为显著;而加入 transformer 后,虽然性能差距会有所收窄,但依然非常明显。
看最新基准测试的 raw 数值,别只看性能倍数宣传
从最新的 bench 脚本(bench/run.mjs)来看,在统一测试环境(MacBook M1,执行 200 次构建并取 75% 分位时间)下,曾得到以下更具参考价值的真实数据:
unocss v0.58.5(仅启用@unocss/preset-uno+@unocss/transformer-directives):328.39 mstailwindcss v3.4.1(默认配置 + 相同规模的@apply使用量):798.42 msnone(不使用 CSS 框架的基线结果):19.92 ms
需要注意的是,这个 2.52× 的差距属于“带负载”的测试结果——因为双方都启用了 @apply,这意味着 UnoCSS 同样会触发 css-tree 的 AST 解析流程。如果你的项目中本身并不使用 @apply,那么 UnoCSS 可以直接跳过 AST 阶段,此时与 Tailwind CSS 的速度差距可能扩大到 4–5×。
为什么实测性能差异会出现较大浮动
核心问题不只是“引擎本身快不快”,而在于“它在什么阶段开始处理任务”:
- Tailwind 的 JIT 属于静态扫描模式:它会读取整个
contentglob 范围内的所有文件,逐行通过正则匹配疑似类名,再进行规则生成。文件数量越多,或者包含大量 MDX 内容、注释文本时,I/O 与匹配成本就会明显增加 - UnoCSS 默认采用 extractor 提取机制:在开发阶段依赖 Vite 插件拦截单个
.vue或.tsx文件,在内存中对模板字符串进行轻量正则提取,不经过 AST;只有到构建阶段才会进行预扫描,而且通常只扫描真正被 import 的模块路径 - 动态类名支持能力也会影响测试结果:例如
class={`text-${color}-500`},Tailwind 通常需要配置safeList或白名单正则,否则容易漏提;而 UnoCSS 的@unocss/extractor-regex可以匹配命中的字面量部分(例如text-red-500),但变量分支依旧无法直接推断
自己评估 UnoCSS 和 Tailwind CSS 性能时,必须控制这 3 个变量
否则测试结果基本没有可比性:
- 构建工具链必须一致:建议统一使用
vite@5+@vitejs/plugin-react,并关闭其他 CSS 相关插件干扰(例如postcss对 Tailwind 是必要依赖,但对 UnoCSS 而言往往属于额外干扰项) content配置必须完全一致:例如都设置为['src/**/*.{ts,tsx,vue}'],不能出现 Tailwind 扫描src/**/*,而 UnoCSS 只扫描src/components/**/*这种范围不一致的情况- 测试前要禁用缓存:Vite 的
.vite/deps和 UnoCSS 的.unocss-cache都应清理干净,使用冷启动方式测试;同时重复执行 200 次,并取 75% 分位数,而不是简单看平均值
实际上,很多开发者容易忽略的一点是:UnoCSS 的性能优势在 HMR(热更新)阶段往往体现得更明显——当你只修改一个组件时,Tailwind 可能仍然需要重新执行整套 CSS 构建流程,而 UnoCSS 通常只需按需注入几条新增规则。这种开发体验上的差别,往往很难单纯通过毫秒级 benchmark 数字完整体现,更适合在你实际编写代码、频繁修改 class 时亲自感受。
