WSの小屋

前言

原子化 CSS(Atomic CSS)是近年来前端样式方案的重要趋势。从 Tailwind CSS 的一统天下,到 Windi CSS 的性能革新,再到 UnoCSS 的极致灵活——三者的演化折射出前端工程化对「DX(开发体验)」与「性能」的不懈追求。

本文将从概念起源、核心原理、横向对比、演化脉络四个维度,全面解析三大原子化 CSS 引擎。


一、原子化 CSS 的概念与起源

1.1 什么是原子化 CSS?

传统 CSS 按语义命名(如 .card-title.user-avatar),而原子化 CSS 将样式拆解为最小粒度的单一功能类:

<!-- 传统 CSS -->
<div class="card-title">Hello</div>

<!-- 原子化 CSS -->
<div class="text-xl font-bold text-gray-800">Hello</div>

每个类只做一件事:text-xl 控制大小,font-bold 控制粗细,text-gray-800 控制颜色。

1.2 为什么需要原子化 CSS?

传统 CSS 的痛点:

  1. 命名困难.card-title vs .card__title vs .cardTitle?BEM、OOCSS、SMACSS 各种规范争战不休
  2. 样式冲突:全局作用域下,类名重复、优先级覆盖是家常便饭
  3. 死代码:项目迭代中,CSS 文件只增不减,大量未使用的样式堆积
  4. 包体积膨胀:CSS 随功能线性增长

原子化 CSS 的优势:

  • 无需命名:直接用功能类组合
  • 无冲突:原子类不依赖 DOM 结构
  • 按需生成:只有用到的类才会被生成
  • 天然摇树优化:不使用 = 不打包

1.3 起源:Functional CSS

原子化 CSS 思想起源于 2013 年左右的 Functional CSS(也叫 immuttable CSS),代表项目有 Tachyons、Basscss。它们预定义了大量原子类,但需要在 HTML 中组合使用。

<!-- Tachyons (2014) -->
<div class="f4 fw6 dark-gray">Hello</div>

缺点是:全量预定义,无论是否使用,所有类都会打包进 CSS,导致文件巨大(Tachyons 完整版 ~300KB)。


二、Tailwind CSS:打破僵局的先行者

2.1 核心理念

Tailwind CSS 于 2017 年由 Adam Wathan 发布,核心理念是 utility-first——用工具类构建 UI,而不写自定义 CSS。

2.2 核心特性

约束式设计系统

Tailwind 预定义了一套设计令牌(spacing、color、font-size 等),所有工具类基于这套约束生成:

// tailwind.config.js
module.exports = {
  theme: {
    spacing: {
      0: '0px',
      1: '0.25rem', // 4px
      2: '0.5rem',  // 8px
      4: '1rem',    // 16px
      8: '2rem',    // 32px
    },
    colors: {
      gray: {
        100: '#f7fafc',
        800: '#2d3748',
      }
    }
  }
}

使用时只能使用预定义的值:

<div class="p-4 text-gray-800">约東下的样式</div>
<div class="p-[13px]">也可以用任意值(JIT 模式)</div>

JIT 模式(v3.0+)

Tailwind v3 引入 Just-In-Time 编译器,移除了早期版本的混淆(purge)机制:

<!-- 任何在源文件中出现的类都会被即时生成 -->
<div class="grid grid-cols-[200px_minmax(900px,_1fr)_100px]">
  自定义网格
</div>

JIT 的优势:

  • 零等待:按需生成,不再全量生成后过滤
  • 任意值w-[345px]text-[#1da1f2] 等不再需要配置
  • 变体组合hover:dark:focus:bg-red-500 可任意组合

插件生态

// tailwind.config.js
plugins: [
  require('@tailwindcss/forms'),
  require('@tailwindcss/typography'),
  require('@tailwindcss/aspect-ratio'),
]

2.3 工作原理

Tailwind 使用 PostCSS 插件在构建时扫描源文件,匹配类名后生成对应 CSS:

源文件 → PostCSS 扫描 → 匹配类名 → 生成 CSS → 写入产出文件

扫描策略:

content: [
  './src/**/*.{html,js,ts,jsx,tsx,vue}',
  './components/**/*.{vue,js,ts}'
]

2.4 优缺点

优点:

  • 生态成熟,社区庞大
  • 插件丰富
  • 文档详尽
  • 设计约束强,适合团队统一规范

缺点:

  • 构建速度慢:PostCSS 扫描 + 生成,大型项目 HMR 延迟明显
  • 配置繁重tailwind.config.js 在大型项目中可能上千行
  • 框架耦合:与构建工具深度绑定,灵活性有限

三、Windi CSS:性能革命的开拓者

3.1 诞生背景

Windi CSS 于 2021 年发布,作者Forrest Liu 直指 Tailwind 的性能瓶颈:

"Tailwind 的 PostCSS 构建在大型项目中越来越慢,我们需要一个更快的替代品。"

3.2 核心特性

按需生成(On-demand)

Windi 不预生成任何 CSS,而是在运行时分析源文件,只生成实际使用到的类:

源文件 → AST 解析 → 提取类名 → 按需生成 CSS → 注入 HMR

预飞行(Preflight)

/* Windi 的 reset 样式自带在运行时 */
*,::before,::after { box-sizing: border-box; border: 0 solid; }

变体分组

<!-- Tailwind 写法 -->
<div class="hover:bg-gray-100 hover:text-gray-800 hover:font-bold md:flex md:flex-col">

<!-- Windi 变体分组 -->
<div class="hover:(bg-gray-100 text-gray-800 font-bold) md:(flex flex-col)">

扫描优化

Windi 使用自定义 AST 解析器替代正则扫描,准确度更高,速度更快。

3.3 性能对比

在大型项目中,Windi 的构建速度可达 Tailwind 的 20~100 倍

项目规模 Tailwind v2 (秒) Windi (秒)
小型 0.8s 0.2s
中型 3.5s 0.3s
大型 (1000+ 组件) 12s 0.5s

3.4 兼容性

Windi 设计为 Tailwind 的严格超集,配置文件兼容,可直接迁移:

// windi.config.js / tailwind.config.js
export default {
  theme: { /* 完全兼容 */ },
  plugins: [/* 兼容 Tailwind 插件 */],
}

3.5 缺点与局限

  • 维护停滞:2022 年后作者精力转向 UnoCSS,Windi 基本停止更新
  • 配置复杂度:虽然兼容 Tailwind,但高级特性需要自己的配置方式
  • 生态依赖:仍依赖 Tailwind 的插件生态,自身无单独插件体系

四、UnoCSS:极致灵活的引擎

4.1 设计哲学

UnoCSS 于 2021 年底由 Anthony Fu 发布。设计哲学是 "不是框架,是引擎"——不提供预设样式,而是提供规则引擎,让用户定义自己的原子类系统。

4.2 核心特性

规则即引擎

// uno.config.ts
import { defineConfig, presetUno } from 'unocss'

export default defineConfig({
  presets: [presetUno()], // 类似 Tailwind 的预设
  rules: [
    // 自定义规则:类名 → CSS
    ['m-1', { margin: '0.25rem' }],
    // 动态规则:正则匹配
    [/^m-(\d+)$/, ([, d]) => ({ margin: `${d / 4}rem` })],
    // 自定义属性
    ['card', { 'border-radius': '8px', padding: '16px' }],
  ]
})

预设系统

import { defineConfig } from 'unocss'

export default defineConfig({
  presets: [
    presetUno(),        // Tailwind/Windi 兼容预设
    presetAttributify(), // 属性化模式
    presetIcons(),       // 图标预设
    presetTypography(),  // 排版预设
    presetWebFonts(),    // 网络字体
    presetWind(),        // Tailwind v3 兼容
    // presetContainerQueries(), // 容器查询
  ],
})

属性化模式

<!-- 原子类写法 -->
<div class="p-4 text-center text-gray-800">

<!-- UnoCSS attributify 写法 -->
<div p-4 text-center text-gray-800>

图标支持

<!-- 直接用类名引入任何图标库的图标 -->
<i class="i-mdi-account"></i>
<i class="i-logos-vue"></i>
<i class="i-carbon-sun dark:i-carbon-moon"></i>

原理:presetIcons 将图标 ID 映射到 CSS background-image,按需加载图标 SVG。

变体分组

<div class="hover:(bg-gray-100 text-gray-800) md:(flex flex-col)">

shortcuts:组合类

shortcuts: {
  'btn': 'px-4 py-2 rounded inline-block cursor-pointer',
  'btn-primary': 'btn bg-blue-500 text-white hover:bg-blue-600',
  'btn-danger': 'btn bg-red-500 text-white hover:bg-red-600',
}
<button class="btn-primary">Primary Button</button>

自动按需变体

<!-- 不需要预设所有变体组合,按需生成 -->
<div class="dark:hover:focus:sm:bg-red-500">
  任意变体组合
</div>

4.3 性能优势

UnoCSS 的构建过程不依赖 AST 解析,而是用正则提取 + 规则匹配的超快策略,构建速度比 Windi 还快 5x+:

引擎 构建速度 CSS 大小
Tailwind v3 1.2s 8.5KB
Windi CSS 0.3s 7.8KB
UnoCSS 0.05s 5.2KB

4.4 生态集成

UnoCSS 是构建工具无关的,支持:

// Vite
import UnoCSS from 'unocss/vite'

// Webpack
const UnoCSS = require('@unocss/webpack')

// PostCSS
const UnoCSS = require('@unocss/postcss')

// CLI
npx unocss 'src/**/*.html' -o build.css

// Nuxt
export default defineNuxtConfig({
  modules: ['@unocss/nuxt']
})

五、三者横向对比

5.1 功能对比表

特性 Tailwind CSS Windi CSS UnoCSS
构建工具 PostCSS 插件 自定义 AST 独立引擎 + 插件
扫描方式 正则 AST 解析 超快正则
JIT 模式 v3+ 支持 原生支持 原生支持
任意值 [xxx] [*] [*] + 动态规则
变体分组
属性化模式
内置图标 ✅ (presetIcons)
shortcuts @apply
自定义规则 配置主题 配置主题 规则引擎 + 预设
插件体系 JS 插件 兼容 TW 自成体系
框架集成 多框架 多框架 多框架 + 原生
构建速度 最快
CSS 体积 最小
维护状态 活跃维护 已停滞 活跃维护

5.2 设计理念对比

Tailwind : 一套完整的设计系统 + 工具类生成器
  ↓
Windi    : 更快的 Tailwind 兼容替代品
  ↓
UnoCSS   : 通用原子 CSS 引擎,一切皆规则
  • Tailwind 适合:需要完整设计约束的团队项目
  • Windi 适合:已用 Windi 的老项目(新项目不推荐)
  • UnoCSS 适合:需要极致性能与灵活性的项目

六、演化脉络与未来趋势

6.1 时间线

2013  Tachyons / Basscss  → Functional CSS 芳芽
  ↓
2017  Tailwind CSS v1     → Utility-first + 约束式设计系统
  ↓
2020  Tailwind CSS v2     → 混淆机制优化、暗色模式
  ↓
2021  Windi CSS           → 按需生成 + 变体分组、超越性能
  ↓
2021  Tailwind CSS v3     → JIT 模式、任意值
  ↓
2021  UnoCSS             → 引擎理念 + 预设 + 插件体系
  ↓
2023  Tailwind CSS v4     → Oxide 引擎(Rust 重写) + 性能 10x
  ↓
2024  UnoCSS             → 容器查询、分层、可持续演进

6.2 Tailwind v4 的回应

Tailwind v4 用 Rust 重写了核心引擎 Oxide,构建速度提升了 10 倍以上,回应了 UnoCSS 的性能挑战:

// @tailwindcss/vite (v4)
import tailwindcss from '@tailwindcss/vite'

export default {
  plugins: [tailwindcss()]
}

面向配置零化:

/* 不需要 tailwind.config.js,直接在 CSS 中用 @theme */
@import "tailwindcss";

@theme {
  --color-my-blue: #1da1f2;
  --spacing-my-1: 0.375rem;
}

6.3 趋势观察

  1. 引擎竞赛:构建速度已经不是瓶颈,三者都在秒下级别
  2. 配置零化:Tailwind v4 去掉 JS 配置,UnoCSS 零配置启动
  3. 跨工具兼容:UnoCSS 的 presetWind 兼容 Tailwind v4 语法
  4. 生态融合:Tailwind 插件可以被 UnoCSS 预设复用
  5. DX 优先:属性化、变体分组、shortcuts 等成为标配

七、选型建议

7.1 新项目选型

场景 推荐
React/Next.js 生态 Tailwind CSS v4
Vue/Nuxt 生态 UnoCSS
需要图标 + 属性化 + 分组 UnoCSS
需要严格设计约束 Tailwind CSS
极致性能追求 UnoCSS
已有 Tailwind 项目升级 Tailwind v4 或注移 UnoCSS

7.2 迁移建议

从 Tailwind 迁移到 UnoCSS:

// 1. 安装 UnoCSS
pnpm add -D unocss @unocss/preset-wind

// 2. 配置文件
import { defineConfig, presetWind, presetAttributify, presetIcons } from 'unocss'

export default defineConfig({
  presets: [
    presetWind(), // Tailwind 兼容预设
    presetAttributify(),
    presetIcons(),
  ],
  // 复用原主题配置
  theme: {
    colors: { /* tailwind.config.js colors */ },
    spacing: { /* tailwind.config.js spacing */ }
  }
})

// 3. Vite 配置
import UnoCSS from 'unocss/vite'
export default {
  plugins: [UnoCSS()]
}

大多数类名可直接复用,变体写法兼容。


八、总结

三大原子化 CSS 引擎反映了前端样式方案的三个阶段:

  1. Tailwind CSS:开创 utility-first 范式,以约束式设计系统定义了一代人写 CSS 的方式
  2. Windi CSS:以性能革命推动 Tailwind 迭代 JIT,虽衰灭火但其精神延续
  3. UnoCSS:以引擎理念超越框架,规则驱动的无穷可能让原子 CSS 更上层楼

三者并非单纯竞争关系,而是相互促动:Windi 推动 Tailwind 引入 JIT,UnoCSS 推动Tailwind v4 用 Rust 重写引擎。这种良性竞争最终造福了整个前端生态。

选择哪个不是关键,理解原子化 CSS 的核心思想——用功能粒度代替语义粒度——才是最重要的。在这个基础上,无论是 Tailwind、UnoCSS 还是未来可能出现的新引擎,都只是具体实现。


延伸阅读

Comments | 0条评论