Tailwind CSS v4 的 CSS-first 配置(@import "tailwindcss"、@theme)改变了什么?
v4 把配置从 tailwind.config.js 搬进了 CSS:用 @import "tailwindcss" 代替三条 @tailwind 指令,用 @theme 定义主题变量,变量的命名空间决定会生成哪些工具类,编译后还会输出成普通 CSS 变量。源文件改为自动扫描,用 @source 补充或排除;JS 配置要用 @config 显式加载。v4 依赖 @property、color-mix() 等新特性,面向 Safari 16.4+、Chrome 111+、Firefox 128+。
简答
v3 项目里,主题色、字体、断点都写在
tailwind.config.js里,CSS 文件开头写三条@tailwind指令。v4 把这些都搬进了 CSS:开头只写一行@import "tailwindcss",主题用@theme { --color-brand: ...; }定义。
@theme里的变量不只是 CSS 变量。变量名的前缀决定生成哪类工具类,写了--color-mint-500,就有了bg-mint-500、text-mint-500;写了--breakpoint-3xl,就有了3xl:变体。编译后这些变量还会输出到:root上,组件样式和 JavaScript 都能直接用var(--color-mint-500)。好处是配置和样式在一个地方,主题值天然是运行时的 CSS 变量,不再需要
resolveConfig把配置导给 JS。扫描源文件也变成了自动的,不用再写content数组,特殊路径用@source补充。要注意几点。旧的 JS 配置不会再被自动读取,要用
@config显式加载,safelist、corePlugins等选项不再支持。v4 依赖@property、color-mix()等新 CSS 特性,官方说面向 Safari 16.4+、Chrome 111+、Firefox 128+,要支持更老的浏览器只能继续用 v3.4。
一个 v4 项目的入口 CSS 长什么样
@import "tailwindcss";
@theme {
--font-display: "Satoshi", "sans-serif";
--breakpoint-3xl: 120rem;
--color-mint-500: oklch(0.72 0.11 178);
}
第一行代替了 v3 的 @tailwind base、@tailwind components、@tailwind utilities。v4 自己处理 @import 和浏览器前缀,升级指南说用 PostCSS 时可以去掉 postcss-import 和 autoprefixer。PostCSS 插件也移到了单独的 @tailwindcss/postcss 包;用 Vite 的项目,官方推荐改用 @tailwindcss/vite 插件。
@theme 里定义了三个变量,接下来就能在 HTML 里写 font-display、3xl:grid-cols-6、bg-mint-500。这几个类原本不存在,是因为定义了对应的变量才有的。
为什么 @theme 不直接写成 :root
官方文档的解释是,主题变量除了是 CSS 变量,还告诉 Tailwind 要生成哪些工具类,所以用专门的语法让这件事显式化。主题变量还必须写在顶层,不能嵌在选择器或媒体查询里,专门的语法方便强制这一点。
变量按命名空间对应工具类:--color-* 对应 bg-*、text-*、fill-* 这类颜色工具类,--font-* 对应 font-*,--breakpoint-* 对应响应式变体。像 flex、object-cover 这种值固定的工具类不受主题影响;bg-red-200、font-serif 能直接用,是因为默认主题定义了 --color-red-200、--font-serif。
所以选择规则很简单:希望这个值变成工具类,就写进 @theme;只是普通的 CSS 变量,不需要对应的工具类,就照常写在 :root 里。
怎样扩展、覆盖和清空默认主题
在 @theme 里写一个新变量就是扩展,写一个同名变量就是覆盖。要整组换掉,用星号语法把命名空间设成 initial:
@import "tailwindcss";
@theme {
--color-*: initial;
--color-brand: oklch(0.6 0.15 250);
--color-surface: oklch(0.98 0 0);
}
这样默认的 red-500、blue-500 都没了,只剩 brand 和 surface 两个颜色。写 --*: initial 则清空整个默认主题,只用自己定义的值。
主题变量引用别的变量时为什么要加 inline
先看一个问题:@theme { --font-sans: var(--font-inter); },然后在某个子元素上才定义 --font-inter。文档说这时文字会退回 sans-serif,而不是 Inter。
原因在 CSS 变量的解析规则:var(--font-sans) 在定义 --font-sans 的那个元素上求值,那里还没有 --font-inter,后面子元素再定义也来不及了。
改法是写 @theme inline { --font-sans: var(--font-inter); }。加了 inline,生成的 .font-sans 会直接写成 font-family: var(--font-inter),跳过中间那层变量,就在使用的元素上求值了。
主题值怎样给 JavaScript 和组件样式用
文档说,所有主题变量在编译时都会变成普通的 CSS 变量,输出在 :root 上。默认只输出用到的变量,想全部输出可以写 @theme static。
v3 提供了 resolveConfig,把 JS 配置展开成对象给其他代码用。v4 去掉了它,官方建议直接用生成的 CSS 变量,比如动画库可以直接把 var(--color-blue-500) 当目标值;确实需要具体值时,用 getComputedStyle 从根元素读取。这种“主题值就是 CSS 变量”的做法,和《设计 token 为什么比散落的颜色变量更适合大型前端项目?》讲的分层 token 可以直接对接。
不写 content 以后,Tailwind 扫描哪些文件
v3 要在配置里写 content 数组列出模板文件。v4 默认扫描项目里的所有文件,跳过 .gitignore 里的文件、node_modules、图片和压缩包这类二进制文件,以及 CSS 文件。扫描本身的原理,即“只为源码里出现的完整类名生成 CSS”,见《CSS-in-JS 和原子化 CSS 怎么选?styled-components、Tailwind、CSS Modules 各适合什么场景?》。
依赖通常在 .gitignore 里,所以用到一个基于 Tailwind 写的组件库时,要用 @source "../node_modules/@acmecorp/ui-lib" 显式加进来;不想扫描的目录用 @source not;完全不要自动检测,就在导入时写 source(none),再逐个注册路径。
从 v3 升级要注意什么
官方提供了升级工具 npx @tailwindcss/upgrade,需要 Node.js 20 或更高版本,会更新依赖、把配置文件迁移成 CSS、改写模板里的类名。文档建议在新分支上运行,然后检查差异并在浏览器里测试。
几处需要人工确认的变化:
- JS 配置文件不再被自动发现。还要用的话写
@config "../../tailwind.config.js",但corePlugins、safelist、separator不再支持,安全名单改用@source inline()。 - v3 里写在
@layer utilities、@layer components里的类会被当成工具类,能配合hover:这类变体。v4 改用原生层叠层,不再接管@layer,自定义工具类要改写成@utility。 - JS 插件用
@plugin "@tailwindcss/typography"加载。 - 深色模式默认跟随
prefers-color-scheme;想用类名或属性手动切换,写@custom-variant dark (&:where(.dark, .dark *));。
浏览器要求是决定能不能升级的硬条件。升级指南说 v4 依赖 @property 和 color-mix() 实现核心功能,在更老的浏览器里无法工作,这些浏览器的支持情况见《oklch()、color-mix() 和相对颜色语法怎样做主题色?》。
常见追问
v4 里还能用 tailwind.config.js 吗?
能,但要在 CSS 里用
@config显式加载,v4 不再自动查找它。官方说@config、@plugin可以和@theme、@utility混用,方便一步步把配置迁到 CSS 里。safelist、corePlugins、separator这几个选项不再支持。
Vue 单文件组件的 style 里用 @apply 报找不到类,怎么办?
组件的
<style>块是单独处理的,看不到主样式表里的主题变量和自定义工具类。文档的办法是在块里写@reference "../../app.css",只引用、不重复输出样式;没有自定义主题时可以直接@reference "tailwindcss"。
为什么 v4 生成的颜色是 oklch?
官方博客说 v4 重新设计了调色板,改成更鲜艳的 P3 色域颜色,默认主题里的颜色变量都用
oklch()定义,比如--color-red-50: oklch(0.971 0.013 17.38)。这也是它对浏览器版本有要求的原因之一。