Tailwind-主题变量
使用 utility 类作为您的设计令牌的 API。
使用 utility 类作为您的设计令牌的 API。
概述
Tailwind 是一个用于构建自定义设计的框架,不同的设计需要不同的排版、颜色、阴影、断点等等。
这些底层的设计决策通常被称为设计令牌,在 Tailwind 项目中,您将这些值存储在主题变量中。
什么是主题变量?
主题变量是使用 @theme 指令定义的特殊 CSS 变量,它会影响项目中存在的 utility 类。
例如,您可以通过定义类似 --color-mint-500 的主题变量,向您的项目添加新的颜色
@import "tailwindcss";
@theme {
--color-mint-500: oklch(0.72 0.11 178);
}现在您可以在 HTML 中使用类似 bg-mint-500、text-mint-500 或 fill-mint-500 的 utility 类
<div class="bg-mint-500">
<!-- ... -->
</div>Tailwind 还会为您的主题变量生成常规 CSS 变量,以便您可以在任意值或内联样式中引用您的设计令牌
<div style="background-color: var(--color-mint-500)">
<!-- ... -->
</div>在主题变量命名空间文档中了解更多关于主题变量如何映射到不同 utility 类的信息。
为什么使用
@theme而不是:root?主题变量不仅仅是 CSS 变量 — 它们还指示 Tailwind 创建新的 utility 类(类似
text-[23px]这种临时的 utility),您可以在 HTML 中使用它们。由于它们的功能比常规 CSS 变量更多,Tailwind 使用特殊的语法,以便主题变量的定义始终是显式的。主题变量也必须在顶层定义,而不是嵌套在其他选择器或媒体查询下,使用特殊语法可以强制执行这一点。
当您想要定义一个不打算连接到 utility 类的变量时,使用
:root定义常规 CSS 变量在 Tailwind 项目中仍然很有用。当您希望设计令牌直接映射到 utility 类时,请使用@theme,而对于不应具有相应 utility 类的常规 CSS 变量,请使用:root。
与 utility 类的关系
Tailwind 中的一些 utility 类(如 flex 和 object-cover)是静态的,并且在每个项目中始终相同。但许多其他 utility 类是由主题变量驱动的,并且仅因您定义的主题变量而存在。
例如,在 --font-* 命名空间中定义的主题变量决定了项目中存在的所有 font-family utility 类
@theme {
--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
/* ... */
}默认情况下,font-sans、font-serif 和 font-mono utility 类之所以存在,是因为 Tailwind 的默认主题定义了 --font-sans、--font-serif 和 --font-mono 主题变量。
如果定义了另一个主题变量(如 --font-poppins),则会提供 font-poppins utility 类来与之配合使用
@import "tailwindcss";
@theme {
--font-poppins: Poppins, sans-serif;
}<h1 class="font-poppins">This headline will use Poppins.</h1>您可以在这些命名空间内随意命名您的主题变量,并且具有相同名称的相应 utility 类将可用于您的 HTML。
与变体的关系
一些主题变量用于定义变体,而不是 utility 类。例如,--breakpoint-* 命名空间中的主题变量决定了项目中存在的响应式断点变体
@import "tailwindcss";
@theme {
--breakpoint-3xl: 120rem;
}
//自定义断点设置现在您可以使用 3xl:* 变体,仅当视口宽度为 120rem 或更宽时才触发 utility 类
<div class="3xl:grid-cols-6 grid grid-cols-2 md:grid-cols-4">
<!-- ... -->
</div>在主题变量命名空间文档中了解更多关于主题变量如何映射到不同 utility 类和变体的信息。
主题变量命名空间
主题变量在命名空间中定义,每个命名空间对应于一个或多个 utility 类或变体 API。
在这些命名空间中定义新的主题变量将在您的项目中提供新的相应 utility 类和变体
| 命名空间 | Utility 类 |
|---|---|
--color-* | 颜色 utility 类,如 bg-red-500、text-sky-300 等等 |
--font-* | 字体族 utility 类,如 font-sans |
--text-* | 字体大小 utility 类,如 text-xl |
--font-weight-* | 字体粗细 utility 类,如 font-bold |
--tracking-* | 字母间距 utility 类,如 tracking-wide |
--leading-* | 行高 utility 类,如 leading-tight |
--breakpoint-* | 响应式断点变体,如 sm:* |
--container-* | 容器查询变体,如 @sm:* 和尺寸 utility 类,如 max-w-md |
--spacing-* | 间距和尺寸 utility 类,如 px-4、max-h-16 等等 |
--radius-* | 边框半径 utility 类,如 rounded-sm |
--shadow-* | 盒阴影 utility 类,如 shadow-md |
--inset-shadow-* | 内阴影 utility 类,如 inset-shadow-xs |
--drop-shadow-* | 阴影投射滤镜 utility 类,如 drop-shadow-md |
--blur-* | 模糊滤镜 utility 类,如 blur-md |
--perspective-* | 透视 utility 类,如 perspective-near |
--aspect-* | 纵横比 utility 类,如 aspect-video |
--ease-* | 过渡 timing 函数 utility 类,如 ease-out |
--animate-* | 动画 utility 类,如 animate-spin |
有关所有默认主题变量的列表,请参阅默认主题变量参考。
默认主题变量
当您在 CSS 文件的顶部导入 tailwindcss 时,它会包含一组默认主题变量以帮助您入门。
以下是您在导入 tailwindcss 时实际导入的内容
@layer theme, base, components, utilities;
@import "./theme.css" layer(theme);
@import "./preflight.css" layer(base);
@import "./utilities.css" layer(utilities);
| @layer 名称 | 用途 | 生效范围 | 典型场景 |
|---|---|---|---|
| theme | 定义设计系统变量 | 全局 | 自定义 CSS 变量、扩展 theme 值 |
| base | 设置全局标签样式 | 全局(自动应用) | 修改 h1/h2 默认样式、重写 reset |
| components | 复用的组件样式 | 需手动添加类 | 自定义按钮、卡片、布局组件 |
| utilities | 新增/覆盖原子类 | 需手动添加类 | 增加自定义工具类,例如 .text-shadow |
theme.css 文件包含默认的调色板、字体比例、阴影、字体等等
node_modules/tailwindcss/theme.css
@theme {
--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--color-red-50: oklch(0.971 0.013 17.38);
--color-red-100: oklch(0.936 0.032 17.717);
--color-red-200: oklch(0.885 0.062 18.334);
/* ... */
--shadow-2xs: 0 1px rgb(0 0 0 / 0.05);
--shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
/* ... */
}这就是为什么像 bg-red-200、font-serif 和 shadow-sm 这样的 utility 类开箱即用的原因 — 它们是由默认主题驱动的,而不是像 flex-col 或 pointer-events-none 那样硬编码到框架中的。
有关所有默认主题变量的列表,请参阅默认主题变量参考。
自定义您的主题
默认主题变量非常通用,适用于构建截然不同的设计,但它们仍然只是一个起点。自定义调色板、字体和阴影等内容以构建您心中所想的确切设计非常常见。
扩展默认主题
使用 @theme 定义新的主题变量并扩展默认主题
@import "tailwindcss";
@theme {
--font-script: Great Vibes, cursive;
}这使得新的 font-script utility 类可用,您可以在 HTML 中使用它,就像默认的 font-sans 或 font-mono utility 类一样
<p class="font-script">This will use the Great Vibes font family.</p>在主题变量命名空间文档中了解更多关于主题变量如何映射到不同 utility 类和变体的信息。
覆盖默认主题
通过在 @theme 中重新定义默认主题变量值来覆盖它
app.css
@import "tailwindcss";
@theme {
--breakpoint-sm: 30rem;
}现在 sm:* 变体将在 30rem 而不是默认的 40rem 视口尺寸下触发
要完全覆盖默认主题中的整个命名空间,请使用特殊的星号语法将整个命名空间设置为 initial
@import "tailwindcss";
@theme {
--color-*: initial;
--color-white: #fff;
--color-purple: #3f3cbb;
--color-midnight: #121063;
--color-tahiti: #3ab7bf;
--color-bermuda: #78dcca;
}当您这样做时,所有使用该命名空间的默认 utility 类*(如 bg-red-500)都将被删除,并且只有您的自定义值(如 bg-midnight)*可用。
在主题变量命名空间文档中了解更多关于主题变量如何映射到不同 utility 类和变体的信息。
使用自定义主题
要完全禁用默认主题并仅使用自定义值,请将全局主题变量命名空间设置为 initial
@import "tailwindcss";
@theme {
--*: initial;
--spacing: 4px;
--font-body: Inter, sans-serif;
--color-lagoon: oklch(0.72 0.11 221.19);
--color-coral: oklch(0.74 0.17 40.24);
--color-driftwood: oklch(0.79 0.06 74.59);
--color-tide: oklch(0.49 0.08 205.88);
--color-dusk: oklch(0.82 0.15 72.09);
}现在,由主题变量驱动的所有默认 utility 类都将不可用,您将只能使用与您的自定义主题变量匹配的 utility 类,如 font-body 和 text-dusk。
定义动画关键帧
在 @theme 中定义 --animate-* 主题变量的 @keyframes 规则,以将它们包含在生成的 CSS 中
app.css
@import "tailwindcss";
@theme {
--animate-fade-in-scale: fade-in-scale 0.3s ease-out;
@keyframes fade-in-scale {
0% {
opacity: 0;
transform: scale(0.95);
}
100% {
opacity: 1;
transform: scale(1);
}
}
}如果您希望您的自定义 @keyframes 规则始终包含在内,即使在不添加 --animate-* 主题变量时也是如此,请在 @theme 外部定义它们。
如何把自定义动画和 Tailwind 的“主题系统”整合在一起,并解释
@theme里定义和在外面定义的区别。在主题里定义一个动画变量
--animate-fade-in-scale,它的值是fade-in-scale 0.3s ease-out→ 这样你就可以在 Tailwind 里用类似animate-[var(--animate-fade-in-scale)]之类的写法引用定义了一个
@keyframes fade-in-scale,用来描述动画过程 → 因为它写在@theme里,所以只有当--animate-fade-in-scale被用到时,Tailwind 才会把这段 keyframes 生成进最终 CSS重点:条件生成 vs 永久生成
“如果您希望您的自定义
@keyframes规则始终包含在内,即使在不添加--animate-*主题变量时也是如此,请在@theme外部定义它们。”意思是:
- 在
@theme里写 keyframes → Tailwind 会把它当成“按需生成”的一部分,只有当你实际用到这个动画变量,才会把 keyframes 输出到最终 CSS- 在
@theme外面写 keyframes → Tailwind 会始终把 keyframes 输出到最终 CSS,不管你有没有用到Tailwind 追求 按需生成 (tree-shaking),减少最终 CSS 体积:
- 如果你的动画只偶尔用到,就放在
@theme里 → Tailwind 只在你真的用到的时候生成- 如果你的动画是全局必须的(比如全局 loading 动画),就放在
@theme外面 → 永远都会输出,避免缺失
定义位置 行为 适用场景 @theme 内 按需生成,只有引用了 --animate-*才会输出 keyframes想保持最终 CSS 尽量小,动画不是每个页面都用 @theme 外 始终生成,哪怕没用到 --animate-*动画是全局必须,或者不怕多输出一些 CSS
--animate-fade-in-scale: fade-in-scale 0.3s ease-out;--animate-fade-in-scale:定义了一个 CSS 自定义属性 (CSS variable)值是
fade-in-scale 0.3s ease-out,对应animation属性的值:
fade-in-scale→ 动画的 @keyframes 名称
0.3s→ 动画持续时间
ease-out → 动画的 timing function这行的作用就是: ✅ 给动画取了一个名字,并把完整的动画声明打包成主题变量
引用其他变量
当定义引用其他变量的主题变量时,请使用 inline 选项
app.css
@import "tailwindcss";
@theme inline {
--font-sans: var(--font-inter);
}使用 inline 选项,utility 类将使用主题变量值,而不是引用实际的主题变量
.font-sans {
font-family: var(--font-inter);
}如果不使用 inline,您的 utility 类可能会因 CSS 中变量的解析方式而解析为意外的值。
<div id="parent" style="--font-sans: var(--font-inter, sans-serif);">
<div id="child" style="--font-inter: Inter; font-family: var(--font-sans);">
This text will use the sans-serif font, not Inter.
</div>
</div>CSS 自定义属性 (CSS variables) 的作用域 + 计算时机 问题,Tailwind 里的
inline是专门用来解决这种“作用域错位”导致的解析 bug 的。我们来拆开分析一下:
#parent定义了--font-sans: var(--font-inter, sans-serif)
- 注意:这里的
var(--font-inter)会在 #parent 的上下文 里立即解析但此时
#parent没有--font-inter,所以解析结果就是sans-serif当浏览器渲染
#child时,它会使用从父级继承下来的--font-sans(已经被解析成sans-serif),即使此时#child上有--font-inter: Inter,也不会重新计算为什么 Tailwind 会受影响
Tailwind 在 v4 里大量用 CSS 变量生成 utility class(例如字体、颜色、间距等),如果你在父级定义了一个变量依赖另一个变量,而那个被依赖的变量只在子级才定义,就会发生和上面一样的“解析提前”的问题。
inline的作用Tailwind 提供的
inline关键字就是解决这个问题的。 它会告诉 Tailwind:不要把这个变量的值提前算好,而是直接原样保留到最终 CSS,让它在使用位置才解析。
换句话说:
- 没有
inline:--font-sans会被当场解析 → 可能得到错误的值- 有了
inline:--font-sans保留原始表达式,等真正用到时才解析 → 能拿到最新的--font-inter
4️⃣ 用
inline改造后的写法Tailwind v4 的推荐写法可能是这样(假设你在 theme 里定义 font family):
@theme { --font-sans: inline var(--font-inter, sans-serif); }这样,Tailwind 会生成的 CSS 保留
var(--font-inter)原样::root { --font-sans: var(--font-inter, sans-serif); /* 不会提前解析 */ }结果就是:
#child定义--font-inter: Inter;- 当浏览器渲染
#child的font-family: var(--font-sans)时- 变量会在
#child的上下文解析,能正确拿到Inter
生成所有 CSS 变量
默认情况下,只有使用的 CSS 变量才会生成在最终的 CSS 输出中。如果您想始终生成所有 CSS 变量,可以使用 static 主题选项
@import "tailwindcss";
@theme static {
--color-primary: var(--color-red-500);
--color-secondary: var(--color-blue-500);
}Tailwind 现在用 CSS 变量来实现 theme 系统
而 static 选项就是控制这些变量是否“按需生成”的开关。
以前(v3 及以前),Tailwind 的 theme 是编译时常量:
- 你在
tailwind.config.js里改颜色 - Tailwind 会直接生成
.bg-red-500 { background-color: #f87171; } - 没有 CSS 变量,值是直接写死的
但从 v4 开始,Tailwind 把 theme 值编译成了 CSS 自定义属性 (CSS variables),例如:
:root {
--color-red-500: #f87171;
--spacing-4: 1rem;
}然后 utility class 变成用变量的形式引用:
.bg-red-500 {
background-color: var(--color-red-500);
}
.p-4 {
padding: var(--spacing-4);
}好处:
- 可以在运行时动态修改主题(比如暗色模式切换、动态换色)
- 可以更好地 tree-shaking(按需生成)
2️⃣ “只有使用的 CSS 变量才会生成”是什么意思
Tailwind v4 默认会“按需生成” CSS 变量:
- 你用了
bg-red-500,它就会生成--color-red-500 - 你没用
bg-blue-500,它就不会生成--color-blue-500
这样最终输出的 CSS 更小。
3️⃣ 什么是 static 选项
如果你不想按需生成,而是希望无论是否用到,都把所有 theme 值变成 CSS 变量输出,就可以在配置里加:
// tailwind.config.js
export default {
theme: {
static: true,
},
};这样就会一次性生成所有变量:
:root {
--color-red-500: #f87171;
--color-blue-500: #3b82f6;
--color-green-500: #22c55e;
/* ...所有 theme 颜色都会生成 */
}跨项目共享
因为 Tailwind v4 的 主题变量是用 CSS 变量写出来的,所以要在多个项目里用同一套主题,只需要把这些变量写进一个单独的 CSS 文件,然后在每个项目里引入这个文件就行。
./packages/brand/theme.css
@theme {
--*: initial;
--spacing: 4px;
--font-body: Inter, sans-serif;
--color-lagoon: oklch(0.72 0.11 221.19);
--color-coral: oklch(0.74 0.17 40.24);
--color-driftwood: oklch(0.79 0.06 74.59);
--color-tide: oklch(0.49 0.08 205.88);
--color-dusk: oklch(0.82 0.15 72.09);
}然后,您可以使用 @import 将您的主题变量包含在其他项目中
./packages/admin/app.css
@import "tailwindcss";
@import "../brand/theme.css";您可以将像这样的共享主题变量放在 monorepo 设置中的自己的包中,甚至将它们发布到 NPM 并像导入任何其他第三方 CSS 文件一样导入它们。
使用您的主题变量
当您编译 CSS 时,您的所有主题变量都会转换为常规 CSS 变量
dist.css
:root {
--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--color-red-50: oklch(0.971 0.013 17.38);
--color-red-100: oklch(0.936 0.032 17.717);
--color-red-200: oklch(0.885 0.062 18.334);
/* ... */
--shadow-2xs: 0 1px rgb(0 0 0 / 0.05);
--shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
/* ... */
}这使得在您的任何自定义 CSS 或内联样式中轻松引用您的所有设计令牌。
使用自定义 CSS
如果你自己写了额外的 CSS 样式,而这些样式里需要用到和 Tailwind 一样的颜色、字体、间距,就直接用 Tailwind 生成的 主题变量,这样才能保证你写的 CSS 和 Tailwind 样式用的是同一套设计值,不会不一致。
app.css
@import "tailwindcss";
@layer components {
.typography {
p {
font-size: var(--text-base);
color: var(--color-gray-700);
}
h1 {
font-size: var(--text-2xl--line-height);
font-weight: var(--font-weight-semibold);
color: var(--color-gray-950);
}
h2 {
font-size: var(--text-xl);
font-weight: var(--font-weight-semibold);
color: var(--color-gray-950);
}
}
}当你拿到一些不是自己写的 HTML(比如从数据库、API 里拿到的 Markdown 转成的 HTML),你没办法给它加上 Tailwind 的类名,这时候就可以用全局样式(比如 @layer base)去统一设置它的样式。
比如你从后端拿到一段文章内容,渲染出来是这样:
<div class="prose-content"> <h1>标题</h1> <p>正文文本</p> <a href="#">一个链接</a> </div>你没办法给
<h1>、<p>每个都加text-xl、mb-4这些 Tailwind 类,这时候你可以在 CSS 里写:@layer base { .prose-content h1 { @apply text-2xl font-bold mb-4; } .prose-content p { @apply mb-2 leading-relaxed; } .prose-content a { @apply text-blue-500 underline; } }这样所有渲染出来的文章都能自动带样式。
使用任意值
在任意值中使用主题变量可能很有用,尤其是在与 calc() 函数结合使用时。
<div class="relative rounded-xl">
<div class="absolute inset-px rounded-[calc(var(--radius-xl)-1px)]">
<!-- ... -->
</div>
<!-- ... -->
</div>在上面的示例中,我们从嵌套的内嵌元素的 --radius-xl 值中减去 1px,以确保它具有同心边框半径。
在 JavaScript 中引用
大多数时候,当您需要在 JS 中引用您的主题变量时,您可以像使用任何其他 CSS 值一样直接使用 CSS 变量。
例如,流行的 React Motion 库允许您动画到和从 CSS 变量值
<motion.div animate={{ backgroundColor: "var(--color-blue-500)" }} />如果您需要在 JS 中访问已解析的 CSS 变量值,您可以使用 getComputedStyle 获取文档根目录上主题变量的值
let styles = getComputedStyle(document.documentElement);
let shadow = styles.getPropertyValue("--shadow-xl");评论
评论加载中……