目前痛点
- 之前的版本体验差。项目使用 tailwindcss,由于 tailwind 在
v2.1+
之后才支持JIT
模式,所有很多随意的宽度(比如w-123
)啥的不支持,要么在全局样式中的某个位置添加这样一个工具类,要么只能在tailwind.config.js
去定义,但是你又不能穷举所有的数字。 - 本地开发会比较慢。tailwind 的
PurgeCSS
这个清除操作仅在生成构建下有效,而开发环境下仍要使用包含了所有规则巨大的 CSS 文件。这在 Webpack 中表现可能并不明显,但在 Vite 中却有着巨大的影响,毕竟其他内容的加载都非常迅捷。 - 性能不是太好。从内部实现上看,Tailwind 依赖于 PostCSS 的
AST
进行修改,并且 Tailwind JIT 依赖于对文件系统的预扫描,并使用文件系统监听器来实现 HMR。文件 I/O 不可避免地会引入开销,而你的构建工具实际上需要再次加载它们。 - WindiCSS 已不再维护
UnoCSS 介绍
虽然目前 Tailwind 还不错,但是 UnoCSS 有更大的优势:
- 直观且完全可定制。像 Tailwind 的一些约定是内置的,你不能随意修改
- 预设功能。通过预设功能,可以直接支持 Tailwind/WindiCSS…的写法;并且可以共享给他人你的自定义预设。
- 跳过解析,不使用 AST。性能更好。
- 其他优势:
- 纯 CSS 图标
- 可变修饰 (Variants)
- 属性化模式 (Attributify Mode)
- CSS 作用域
- Shortcuts:多个原子合成一个
- 网络字体
- …
UnoCSS和TailWind的区别
UnoCSS 和 Tailwind CSS 都是现代 CSS 解决方案,旨在提高开发效率和体验,但它们在设计理念、功能和工作方式上存在一些关键区别。
1. 核心理念与定位:
- Tailwind CSS: 是一个功能类优先 (utility-first) 的 CSS 框架。它提供了一整套预设的、低层级的 CSS 功能类,开发者可以直接在 HTML 中组合这些类来构建用户界面,而无需编写太多的自定义 CSS。最新版本的 Tailwind CSS 采用即时 (JIT) 编译器,按需生成 CSS,从而减小最终的 CSS 文件大小。
- UnoCSS: 更像是一个按需原子化 CSS 引擎 (on-demand atomic CSS engine) 或元框架。它本身不提供任何核心功能类,所有功能都通过预设 (presets) 提供。这意味着你可以选择性地加入你需要的功能,甚至可以创建自己的规范、设计系统和预设。它的核心思想是极致的灵活性和性能。
2. CSS 生成方式:
- Tailwind CSS: 虽然现代版本使用 JIT 按需生成,但其设计初衷是拥有一套庞大的预定义功能类集。JIT 会扫描你的模板文件,只生成用到的 CSS。
- UnoCSS: 严格按需生成。它只在你代码中实际用到了某个类时才会生成对应的 CSS 规则。这种方式通常能带来更快的构建速度和更小的最终产物。
我们用一个更具体的例子来说明它们核心理念上的区别,尤其是在 “如何提供和生成CSS” 以及 “灵活性” 这两个方面。
想象一下你要给一个按钮添加样式:红色背景、白色文字、一些内边距。
使用 Tailwind CSS (JIT 模式)
Tailwind CSS 本身提供了一整套预先定义好的功能类名。当你使用它的时候,你是在这些已经存在的类名中进行选择。
<button class="bg-red-500 text-white py-2 px-4 rounded">
Click Me
</button>
-
核心区别点1:预定义的功能类库
bg-red-500
,text-white
,py-2
,px-4
,rounded
这些都是 Tailwind CSS 内置定义好的功能类。- 在构建时,Tailwind 的 JIT (Just-In-Time) 编译器会扫描你的 HTML 文件,找到你用到的这些类名 (如
bg-red-500
),然后只为这些用到的类生成对应的 CSS 规则到最终的 CSS 文件中。 - 它像一个巨大的工具箱,里面有各种工具(CSS类),你挑着用,JIT 帮你把用到的打包。
-
核心区别点2:通过配置文件进行定制
- 如果你想改变
red-500
具体是什么红色,或者想增加一个新的颜色brand-blue
,你会去修改tailwind.config.js
文件。
// tailwind.config.js module.exports = { theme: { extend: { colors: { 'brand-blue': '#007bff', }, }, }, // ... }
然后你就可以用
bg-brand-blue
了。 - 如果你想改变
使用 UnoCSS
UnoCSS 更像是一个 CSS 规则生成引擎。它默认情况下不包含任何具体的 CSS 功能类。你需要通过预设 (presets) 或自定义规则来告诉它如何生成你想要的 CSS。
方式一:使用类似 Tailwind 的预设 (@unocss/preset-wind
)
你可以选择一个预设,比如 @unocss/preset-wind
,这个预设会使 UnoCSS 的行为方式非常接近 Tailwind CSS。
<button class="bg-red-500 text-white py-2 px-4 rounded">
Click Me
</button>
- 核心区别点1(此模式下):按需生成,但规则来自预设
- 当你写
bg-red-500
时,UnoCSS 会查看@unocss/preset-wind
这个预设。这个预设知道bg-red-500
应该生成什么样的 CSS(比如background-color: #ef4444;
)。 - 它不是从一个庞大的预定义库里找,而是根据预设的规则即时生成。这个过程非常快,因为它只处理你用到的东西。
- 当你写
方式二:极致的灵活性 - 自定义规则或使用特殊预设 (例如 Attributify Mode)
这是 UnoCSS 更能体现其“引擎”特性的地方。
-
使用 Attributify Mode (通过
@unocss/preset-attributify
)首先,你需要在你的 UnoCSS 配置中启用这个预设:
// uno.config.ts import { defineConfig, presetAttributify, presetUno } from 'unocss' export default defineConfig({ presets: [ presetAttributify(), // 启用属性化模式 presetUno(), // 一个基础的预设,提供类似 Tailwind 的功能类 ], })
然后你可以这样写 HTML:
<button bg="red-500" text="white" p="y-2 x-4" rounded> Click Me </button>
或者更简洁地:
<button bg-red-500 text-white p="y-2 x-4" rounded> Click Me </button>
- 核心区别点1:CSS规则的“来源”和“表达方式”更灵活
- 这里,
bg="red-500"
、text="white"
不再是class
属性里的类名,而是直接作为 HTML 元素的属性。 - UnoCSS 引擎会识别这些属性(根据
presetAttributify
的规则),并动态地为它们生成相应的 CSS。例如,看到bg="red-500"
,它会生成background-color: #ef4444;
。
- 这里,
- 核心区别点2:引擎驱动,而非固定框架
- UnoCSS 本身不“拥有”
bg-red-500
这个概念。是 预设 (preset) 告诉了 UnoCSS 引擎:“当你看到bg-red-500
这样的模式时,请生成对应的背景颜色 CSS”。 - 这意味着你可以创建完全自定义的预设或规则,让 UnoCSS 生成任何你想要的 CSS,甚至是你自己发明的简写。比如你可以定义一个规则,让
my-button-style
直接生成上面按钮的所有样式。
- UnoCSS 本身不“拥有”
- 核心区别点1:CSS规则的“来源”和“表达方式”更灵活
总结核心区别的例子:
- Tailwind CSS: 给你一本厚厚的、包含各种标准工具的说明书和工具箱 (预定义的功能类)。你需要什么样式,就按照说明书去工具箱里找对应的工具(类名)来组合使用。JIT 编译器会帮你把用到的工具打包。你想增加新工具或修改现有工具,主要通过修改其配置文件 (说明书的附录)。
- UnoCSS: 给你一个高度智能的、可编程的机器人 (CSS 引擎)。
- 你可以给这个机器人加载不同的 技能包 (presets)。加载了“Tailwind 技能包” (
@unocss/preset-wind
),它的行为就和 Tailwind 很像。加载了“属性化技能包” (@unocss/preset-attributify
),它就能理解直接写在属性里的样式。 - 你甚至可以教机器人全新的技能 (自定义规则),比如告诉它:“以后看到
crazy-style
这个词,就生成一套特定的 CSS”。 - 它不依赖于一个固定的“类名清单”,而是根据你提供的规则和实际用到的代码,动态地、即时地生成 CSS。
- 你可以给这个机器人加载不同的 技能包 (presets)。加载了“Tailwind 技能包” (
我可以这样理解吗?Tailwind 是一个“框架”,而UnoCSS 则是生成“框架”的规则。UnoCSS 可以生成Tailwind ,可以生成xxxWind,yyyWind等等
是的,你这样理解在很大程度上是非常准确的!这是一个很好的方式来抓住它们之间的核心区别。
- Tailwind CSS 是一个“框架”:
- 它提供了一整套定义好的功能类 (utilities) 和设计系统约定。
- 你学习并使用这个框架提供的规则和类名。
- 虽然可配置,但其核心结构和主要功能类是预先设定好的。
- UnoCSS 更像是生成这些“框架”的“规则引擎”或“元框架”:
- 它本身不带任何固定的 CSS 类。
- 你可以通过预设 (presets) 来告诉 UnoCSS 你想遵循什么样的规则。
- 比如,使用
@unocss/preset-wind
,UnoCSS 就能理解并生成与 Tailwind CSS 几乎一样的功能类。所以,是的,UnoCSS 可以“生成”出类似 Tailwind CSS 的功能和体验。 - 同理,理论上你可以创建或找到一个预设,让 UnoCSS 生成遵循任何你自定义的命名约定和设计系统的 CSS,比如你所说的 “xxxWind” 或 “yyyWind”。这就是它的强大之处——定义规则,然后按需生成。
- 比如,使用
- 它提供的是一种机制,让你能够创建、组合或模拟不同的原子化 CSS 框架的风格和功能。
更进一步说:
- Tailwind CSS 是一个已经为你准备好的、功能齐全的厨房,里面有各种厨具(类名)和食谱(设计规范)。
- UnoCSS 更像是一个高度可定制的食品加工机器人。你可以给它加载不同的程序(预设):
- 加载“Tailwind 食谱程序”,它就能做出 Tailwind 风格的菜肴。
- 加载你自己的“xxxWind 食谱程序”,它就能按你的独特口味来烹饪。
- 它甚至还能理解一些非常规的操作指令(比如 Attributify 模式,直接在食材上标注做法)。
所以,你的理解“UnoCSS 可以生成 Tailwind,可以生成 xxxWind,yyyWind 等等”是抓住了 UnoCSS 核心的灵活性和引擎特质。它不是简单地“是”一个框架,而是可以“成为”或“驱动”多种框架风格的底层引擎。
何时使用
新项目直接使用 UnoCSS,使用 tailwind 预设,可以直接上手。
老项目的话,tailwind 目前还不是瓶颈,需要的功能都有,暂不需要更新。