AIGC标识 Tailwind CSS v4 vs v3:重写级升级到底改了什么

本文基于一个真实项目(React + TypeScript + Vite 的全屏 Hero 落地页)的实际使用体验,结合官方文档,梳理 Tailwind CSS v4 相对 v3 的全部重大变化。

最后更新:2026-09-08


一句话概括

Tailwind CSS v4 用 Rust 重写了引擎把配置从 JavaScript 搬进了 CSS砍掉了一堆历史包袱类名。结果是构建速度提高 3-10 倍,配置文件从三个减到零,日常开发体验发生了质变。


目录

  1. 引擎:从 Node.js 到 Rust(Oxide)
  2. 配置:从 JS 到 CSS-first
  3. 工具链:从 PostCSS 三件套到单插件
  4. 内容扫描:手动声明 → 自动检测
  5. 类名变更:删、改、缩放位移
  6. 新指令一览
  7. 暗黑模式配置迁移
  8. 实际项目中的代码对比
  9. 迁移路径与注意事项
  10. 性能基准数据
  11. 总结:该不该升级

1. 引擎:从 Node.js 到 Rust(Oxide)

v3 的整个构建管线是 JavaScript 写的(Node.js + PostCSS)。v4 用 Rust 重写了一个叫 Oxide 的新引擎,配合 Lightning CSS 做 CSS 处理。

指标 v3 v4 提升
全量构建 ~378ms ~100ms 3.8x
增量构建(有新类) ~44ms ~5ms 8.8x
增量构建(无新类) ~35ms ~0.2ms 182x
CSS 产物体积 ~24KB ~18KB -25%

数据来自 Tailwind Labs 官方 benchmark(Catalis 项目),2024 年 11 月 v4 beta 公告。

实际体感:开发时 HMR(热模块替换)几乎是"即时"的,项目越大感受越明显。这在大型 React/Vue 应用中改善显著。


2. 配置:从 JS 到 CSS-first

这是 v4 最大的架构变更,也是需要开发者理解的最重要的一条。

v3 的做法

项目根目录需要三个配置文件:

tailwind.config.js      主题插件内容路径全在这
postcss.config.js       PostCSS 插件链
src/index.css           @tailwind base / components / utilities
// tailwind.config.js(v3)
module.exports = {
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {
      colors: {
        brand: '#6366f1',
      },
      fontFamily: {
        display: ['Anton', 'sans-serif'],
        sans: ['Inter', 'sans-serif'],
      },
      borderRadius: {
        '4xl': '2rem',
      },
    },
  },
  darkMode: 'class',
  plugins: [require('@tailwindcss/forms')],
};

v4 的做法

不需要 tailwind.config.js不需要 postcss.config.js。全部配置写进 CSS:

/* src/index.css(v4) */
@import "tailwindcss";

@theme {
  --color-brand: #6366f1;
  --font-display: "Anton", sans-serif;
  --font-sans: "Inter", sans-serif;
  --radius-4xl: 2rem;
}

就这样。整个项目只需要这一个 CSS 文件,配合一个 Vite 插件注册,完事。

关键理解:@theme vs :root

你可能会问:为什么不用 :root { --color-brand: ... }

区别在于 @theme 做了两件事

  1. 定义 CSS 变量(和 :root 一样,运行时可用)
  2. 自动生成对应的工具类

--color-brand: #6366f1 之后,Tailwind 自动产出: - bg-brand - text-brand - border-brand - ring-brand - divide-brand - 以及所有带透明度修饰符的变体:bg-brand/50text-brand/75 等等

:root 只有变量,不会有工具类。这就是 @theme 的核心价值。

命名空间与工具类的映射规则

CSS 变量前缀 生成的工具类 示例
--color-* bg-*text-*border-*ring-* --color-brandbg-brand
--font-* font-* --font-displayfont-display
--spacing-* p-*m-*gap-* --spacing-18p-18
--breakpoint-* 响应式前缀 --breakpoint-3xl3xl:grid-cols-4
--radius-* rounded-* --radius-4xlrounded-4xl
--ease-* ease-* --ease-springease-spring
--animate-* animate-* --animate-fadeanimate-fade

规律:变量名去掉 -- 前缀,就是工具类名。 学一次命名空间,终身受用。


3. 工具链:从 PostCSS 三件套到单插件

v3 的依赖堆栈

npm install tailwindcss postcss autoprefixer

配置 postcss.config.js

module.exports = {
  plugins: {
    'postcss-import': {},
    tailwindcss: {},
    autoprefixer: {},
  },
};

三个包,三个配置项,缺一不可。

v4 的依赖

Vite 项目(推荐):

npm install tailwindcss @tailwindcss/vite
// vite.config.ts
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
  plugins: [tailwindcss()],  // 就这一行
});

@tailwindcss/vite 一个插件包,内置了 CSS 处理、浏览器前缀(autoprefixer)和 Tailwind 编译,不需要 PostCSS 配置文件

PostCSS 项目(Next.js 等):

npm install tailwindcss @tailwindcss/postcss
// postcss.config.mjs
export default {
  plugins: {
    '@tailwindcss/postcss': {},  // 替代三个插件
  },
};

CLI(无构建工具):

npx @tailwindcss/cli -i input.css -o output.css

tailwindcss 包本身不再是 PostCSS 插件了。PostCSS 插件搬到了 @tailwindcss/postcss。如果你的 postcss.config.js 还写着 tailwindcss: {},升级后会静默失效。


4. 内容扫描:手动声明 → 自动检测

v3 必须手写

// tailwind.config.js
module.exports = {
  content: [
    './src/**/*.{js,ts,jsx,tsx,mdx}',
    './components/**/*.{js,ts,jsx,tsx}',
  ],
};

漏写一个路径 → 该目录下的类名不会出现在产物中 → 样式丢失。这是 v3 最常见的 bug 来源之一。

v4 完全自动

不需要任何 content 配置。@tailwindcss/vite 插件在编译时自动扫描项目中所有 .js.ts.tsx.html.md 文件,发现用到的类名就生成对应 CSS。

特殊情况:排除或额外包含

/* 显式添加不在自动扫描范围的来源 */
@source "../node_modules/@my-company/ui-lib";

/* 排除某个目录 */
@source not "../src/components/legacy";

/* 彻底关闭自动检测(极少用) */
@import "tailwindcss" source(none);

5. 类名变更:删、改、缩放位移

这是升级时最容易导致视觉 bug 的部分。v4 对历史遗留类名做了一次大清理。

5.1 删除:Opacity 修饰符

v3:

<div class="bg-blue-500 bg-opacity-50">

v4:

<div class="bg-blue-500/50">  <!-- 斜杠语法,这是唯一写法 -->

所有 *-opacity-* 工具类被移除:bg-opacity-*text-opacity-*border-opacity-*ring-opacity-*divide-opacity-*placeholder-opacity-*

5.2 重命名:缩放阶梯下移一档

v4 在 shadow、rounded、blur 三个尺度的最前面插入了一个更小的档位(xs),原来的 sm 变成了 xs,以此类推。

用途 v3 v4
阴影最小 shadow-sm shadow-xs
阴影默认 shadow shadow-sm
圆角最小 rounded-sm rounded-xs
圆角默认 rounded rounded-sm
模糊最小 blur-sm blur-xs
模糊默认 blur blur-sm

最容易踩的坑: 你写的 shadow-sm 在 v4 里变成了最小阴影(而不是你记忆中的次小阴影),视觉上会"变淡"。升级后逐个对比。

5.3 重命名:语义修正

v3 v4 原因
bg-gradient-to-r bg-linear-to-r 回归 CSS 原生命名(linear-gradient
bg-gradient-to-t bg-linear-to-t 同上
flex-shrink-0 shrink-0 简化
flex-grow grow 简化
overflow-ellipsis text-ellipsis 对齐 CSS 属性名
decoration-slice box-decoration-slice 对齐 CSS 属性名
decoration-clone box-decoration-clone 同上
outline-none outline-hidden outline-none 现在真正设置 outline-style: none

5.4 默认值变更

v3 v4 影响
border 默认颜色 gray-200 currentColor border 类的元素会继承文字颜色
ring 默认宽度 3px 1px 焦点环变细,需要 ring-3 恢复
outline-none 语义 透明 2px 轮廓(保留强制颜色模式) outline-style: none 原行为改名为 outline-hidden

5.5 Hover 行为变更

v4 的 hover: 变体自动包裹在 @media (hover: hover) 内,触摸设备上的"模拟 hover"不再触发。这通常是你想要的行为,但如果你依赖 :active 类似的"按下效果",需要改用 active:


6. 新指令一览

指令 用途 替代的是
@import "tailwindcss" 引入 Tailwind 全部层 @tailwind base; @tailwind components; @tailwind utilities;
@theme { } 定义设计令牌,自动生成工具类 tailwind.config.jstheme.extend
@theme inline { } 映射已有变量到工具类,不生成新变量 无(新功能)
@theme static { } 定义不生成工具类的令牌 无(新功能)
@utility name { } 注册自定义工具类 @layer utilities + @apply
@custom-variant name (selector) 注册自定义变体 tailwind.config.jsvariants
@source 显式添加扫描路径 content 数组
@config 加载旧版 JS 配置(过渡用) 无(兼容桥接)
@reference 在 Vue/Svelte <style> 中引入主题变量 无(新功能)
@plugin 加载旧版 JS 插件 require()

重点:@utility 的用法

v3 里注册自定义工具类需要在 @layer utilities 里写:

/* v3 */
@layer utilities {
  .tab-4 { tab-size: 4; }
}

v4 用 @utility 指令,支持变体(hover、focus 等):

/* v4 */
@utility tab-4 {
  tab-size: 4;
}

/* 自带动画定义能力 */
@utility grain {
  position: absolute;
  inset: 0;
  opacity: 0.16;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,...");
}

theme() 函数已弃用

v3 里在自定义 CSS 里访问主题值:

/* v3(已弃用) */
.foo {
  color: theme('colors.blue.500');
  margin: theme('spacing.12');
}

v4 直接用 CSS 变量:

/* v4 */
.foo {
  color: var(--color-blue-500);
  margin: --spacing(12);
}

7. 暗黑模式配置迁移

v3

// tailwind.config.js
module.exports = {
  darkMode: 'class', // 或 'media'
};

v4

默认行为 = 跟随系统偏好prefers-color-scheme: dark),不需要任何配置。

如果要用 class 策略(在 <html> 上加 .dark 类切换):

@import "tailwindcss";

@custom-variant dark (&:where(.dark, .dark *));

如果要基于 data-theme 属性:

@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));

不再需要写 darkMode: 'class',改为声明式的 CSS variant。


8. 实际项目中的代码对比

以下是我在一个真实 React + Vite 项目里写 v4 配置的完整例子,可以直接对照 v3 的写法。

项目文件结构对比

v3 项目3 个配置文件          v4 项目1  CSS 文件
├── tailwind.config.js          ├── vite.config.ts插件注册
├── postcss.config.js           └── src/index.css@theme 指令
└── src/index.css

src/index.css(完整版)

@import "tailwindcss";

@theme {
  /* 字体:自动生成 font-display、font-sans 工具类 */
  --font-display: "Anton", "Archivo Black", "Impact", system-ui, sans-serif;
  --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;

  /* 颜色:自动生成 bg-ink、text-ink、bg-bone、text-bone 等 */
  --color-ink: #08080a;
  --color-bone: #f4f2ee;
  --color-acid: #d8ff3e;

  /* 缓动:自动生成 ease-out-expo 工具类 */
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
}

/* 自定义工具类 —— v4 用 @utility 替代 @layer utilities */
@utility grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.16;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,...");
}

@utility caret {
  display: inline-block;
  width: 0.06em;
  animation: caret-blink 1s steps(1) infinite;
}

@utility spin-slow {
  animation: spin-slow 12s linear infinite;
}

@keyframes caret-blink { 0%,49% { opacity: 1 } 50%,100% { opacity: 0 } }
@keyframes spin-slow { to { rotate: 360deg } }

JSX 里使用(v3 和 v4 工具类写法完全相同)

// 大部分工具类写法不变
<div className="bg-ink text-bone font-display rounded-full">

// 透明度(v3 的 bg-opacity-* 已移除,必须用斜杠语法)
<div className="bg-black/75">    // 不是 bg-black bg-opacity-75

// 圆角(阶梯下移一档)
<div className="rounded-xs">     // v3 里的 rounded-sm
<div className="rounded-sm">     // v3 里的 rounded

// 模糊
<div className="blur-sm">        // v3 里的 blur
<div className="blur-xs">        // v3 里的 blur-sm

// 渐变(名称回归 CSS 原生)
<div className="bg-linear-to-r"> // 不是 bg-gradient-to-r

// 自定义工具类(直接用 @utility 注册的名字)
<div className="grain">          // 引用 @utility grain
<svg className="spin-slow">      // 引用 @utility spin-slow

9. 迁移路径与注意事项

自动迁移工具

npx @tailwindcss/upgrade

该工具能自动处理约 90% 的迁移工作: - 把 tailwind.config.js 转成 @theme CSS 指令 - 重命名已废弃的类名 - 把 @tailwind 指令换成 @import "tailwindcss" - 更新 PostCSS 配置

不能自动处理的: - 自定义 JS 插件(插件 API 变了) - 复杂的 theme() 函数调用 - 基于 JS 的动态配置逻辑

浏览器兼容性

v4 要求现代浏览器,依赖 @propertycolor-mix() 等 CSS 特性:

浏览器 最低版本
Chrome 111+
Safari 16.4+
Firefox 128+

如果需要兼容更老的浏览器,暂时留在 v3.4

过渡策略

如果项目太大不想一步到位,v4 提供了兼容桥接:

@import "tailwindcss";

/* 继续使用旧版 JS 配置 */
@config "../../tailwind.config.js";

/* 继续使用旧版 JS 插件 */
@plugin "@tailwindcss/typography";

CSS 里定义的 @theme 会与 JS 配置合并,CSS 优先。你可以分步迁移。


10. 性能基准数据

以下数据来自 Tailwind Labs 官方 benchmark,使用 Catalyst 组件库项目:

场景 v3.4 v4 提升
全量构建 378ms 100ms 3.8x
增量构建(新类) 44ms 5ms 8.8x
增量构建(无新类) 35ms 0.2ms 182x

"无新类"场景占比最高——随着项目开发,大部分编辑都只用到已有的工具类,这些构建在微秒级完成。这就是为什么日常开发体感"快了一个量级"。

其他第三方 benchmark(2026):

来源 全量构建 增量构建 CSS 体积
dev.to benchmark ~800ms → ~100ms(8x) ~200ms → ~5ms(40x) 24KB → 18KB(-25%)
Digital Applied 3.5s → <100ms(35x)

实际体感取决于项目规模。类名越多、文件越多,v4 的优势越大。


11. 总结:该不该升级

直接升级的情况

  • 新项目,没有理由用 v3
  • 项目小、有测试覆盖
  • 已经在用 Vite(v4 的 Vite 插件体验最好)
  • 大型项目但有完善的回归测试

暂时观望的情况

  • 大量自定义 PostCSS 插件,插件尚未发布 v4 兼容版本
  • 必须支持 Chrome 111 / Safari 16.4 以下的浏览器
  • 依赖的第三方 UI 库(如 Headless UI、Radix 等)尚未适配 v4

关键差异速查表

维度 v3 v4
配置语言 JavaScript CSS(原生)
配置文件数 2-3 个 0 个
主题定义位置 tailwind.config.js CSS @theme 指令
自定义工具类 @layer utilities @utility 指令
引擎语言 JavaScript Rust
PostCSS 依赖 必须 可选(Vite 项目不需要)
内容扫描 手动 content: [...] 自动
透明度写法 bg-opacity-50 bg-black/50
渐变写法 bg-gradient-to-r bg-linear-to-r
圆角/阴影/模糊 rounded-sm = 0.125rem rounded-sm = 0.25rem(阶梯下移)
border 默认颜色 gray-200 currentColor
ring 默认宽度 3px 1px
hover 触发 无条件 hover: hover 媒体
暗黑模式配置 darkMode: 'class' @custom-variant dark (...)
theme() 函数 可用 已弃用,用 var()
CSS 原生层支持 无(Tailwind 自实现) 有(@layer

附:快速命令对照

# v3 安装
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init

# v4 安装(Vite 项目)
npm install -D tailwindcss @tailwindcss/vite

# v4 安装(PostCSS 项目)
npm install -D tailwindcss @tailwindcss/postcss

# v4 CLI
npm install -D @tailwindcss/cli

# 自动迁移
npx @tailwindcss/upgrade

本文写作过程中使用的真实项目:Mainframe — 全屏 Hero 落地页,基于 React 19 + TypeScript 7 + Vite 8 + Tailwind CSS 4.3 构建。

posted on 2026-09-08 17:46  fox_charon  阅读(3)  评论(0)    收藏  举报

导航