目录
[为什么是 @theme 而不是 :root](#为什么是 @theme 而不是 :root)
[使用 @theme inline](#使用 @theme inline)
Tailwind 是一个用于构建自定义设计的框架,不同的设计需要不同的排版、颜色、阴影、断点等。
这些底层设计决策通常称为设计令牌,在 Tailwind 项目中,你将这些值存储在主题变量中。
什么是主题变量?
主题变量是使用**@theme
**指令定义的特殊 CSS 变量,会影响项目中存在哪些工具类。
例如,你可以通过定义主题变量(如 --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
:
<div class="bg-mint-500">
<!-- ... -->
</div>
Tailwind 还会为你的主题变量生成常规 CSS 变量,以便你可以在任意值或内联样式中引用你的设计令牌:
<div style="background-color: var(--color-mint-500)">
<!-- ... -->
</div>
为什么是 @theme 而不是 :root
主题变量不仅仅是 CSS 变量 - 它们还指示 Tailwind 创建可在 HTML 中使用的新工具类。
由于它们比常规 CSS 变量功能更多,Tailwind 使用特殊语法,因此定义主题变量始终是明确的。主题变量也需要在顶层定义,而不是嵌套在其他选择器或媒体查询下,使用特殊语法可以强制执行这一点。
当你想要定义一个不打算连接到工具类的变量时,使用 :root
定义常规 CSS 变量在 Tailwind 项目中仍然很有用。当你希望设计令牌直接映射到工具类时使用 @theme
,并使用 :root
定义不应具有相应工具类的常规 CSS 变量。
与工具类的关系
Tailwind 中的一些工具类(如 flex
和 object-cover
)是静态的,并且在各个项目之间始终相同。但许多其他效果是由主题变量驱动的,并且仅因你定义的主题变量而存在。
例如,--font-*
命名空间中定义的主题变量确定项目中存在的所有 font-family
工具:
@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
工具仅在默认情况下存在,因为 Tailwind 的默认主题定义了 --font-sans
、--font-serif
和 --font-mono
主题变量。
如果定义了另一个主题变量(如 --font-poppins
),则可以使用 font-poppins
工具类来配合使用:
@import "tailwindcss";
@theme {
--font-poppins: Poppins, sans-serif;
}
<h1 class="font-poppins">This headline will use Poppins.</h1>
你可以在这些命名空间中随意命名主题变量,并且具有相同名称的相应工具将可用于你的 HTML。
主题变量命名空间
主题变量在命名空间中定义,每个命名空间对应一个或多个工具类或变体 API。
在这些命名空间中定义新的主题变量将使新的相应工具和变体在你的项目中可用:
Namespace | Utility classes |
---|---|
--color-* |
Color utilities like bg-red-500 , text-sky-300 , and many more |
--font-* |
Font family utilities like font-sans |
--text-* |
Font size utilities like text-xl |
--font-weight-* |
Font weight utilities like font-bold |
--tracking-* |
Letter spacing utilities like tracking-wide |
--leading-* |
Line height utilities like leading-tight |
--breakpoint-* |
Responsive breakpoint variants like sm:* |
--container-* |
Container query variants like @sm:* and size utilities like max-w-md |
--spacing-* |
Spacing and sizing utilities like px-4 , max-h-16 , and many more |
--radius-* |
Border radius utilities like rounded-sm |
--shadow-* |
Box shadow utilities like shadow-md |
--inset-shadow-* |
Inset box shadow utilities like inset-shadow-xs |
--drop-shadow-* |
Drop shadow filter utilities like drop-shadow-md |
--blur-* |
Blur filter utilities like blur-md |
--perspective-* |
Perspective utilities like perspective-near |
--aspect-* |
Aspect ratio utilities like aspect-video |
--ease-* |
Transition timing function utilities like ease-out |
--animate-* |
Animation utilities like 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);
该 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
这样的工具开箱即用的原因 - 它们由默认主题驱动,而不是像 flex-col
或 pointer-events-none
那样硬编码到框架中。
自定义主题
扩展默认主题
使用 @theme
定义新主题变量并扩展默认主题:
@import "tailwindcss";
@theme {
--font-script: Great Vibes, cursive;
}
这使得你可以在 HTML 中使用新的 font-script
工具类,就像默认的 font-sans
或 font-mono
工具一样:
<p class="font-script">This will use the Great Vibes font family.</p>
引用其他变量
定义引用其他变量的主题变量时,请使用 inline
选项
@import "tailwindcss";
@theme inline {
--font-sans: var(--font-inter);
}
使用
inline
选项,工具类将使用主题变量值而不是引用实际主题变量:
.font-sans {
font-family: var(--font-inter);
}
问题示例
如果不使用 inline
,你的工具类可能会解析为意外值,因为变量在 CSS 中的解析方式不同。、
CSS 变量(custom properties)有"在哪定义就在哪解析"的特点。
这意味着如果你定义了
--a: var(--b)
,那么浏览器在解析--a
的时候,会立刻 尝试去读取--b
的值,而不会等到后面才解析。
例如,此文本将回退到 sans-serif
,而不是像你预期的那样使用 Inter
<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 sans-serif, not Inter.
</div>
</div>
发生这种情况的原因是 var(--font-sans)
在定义 --font-sans
的地方(在 #parent
上)得到解析,而 --font-inter
在那里没有值,因为它直到树的更深层(在 #child
上)才被定义。
-
在
#parent
上定义了--font-sans
:它等于var(--font-inter, sans-serif)
-
这时浏览器会立即解析
--font-inter
的值 -
但
--font-inter
是在#child
中才定义的 -
所以在
#parent
中--font-inter
是 未定义 的 -
因此
var(--font-inter, sans-serif)
只好使用后备值sans-serif
🚨 CSS变量解析的是当前作用域已有的变量,不会往子元素查找!
使用 @theme inline
Tailwind 提供了 @theme inline
这个语法糖来帮助你避免这种问题。
例如:
@theme inline {
--font-sans: var(--font-inter);
}
这个语法的效果是:让 Tailwind 把这个变量的值原封不动地写进最终的工具类中,而不是先计算它。
编译结果如下:
.font-sans {
font-family: var(--font-inter);
}
这样,当 Tailwind 构建 .font-sans
工具类时,它不会试图提前计算 --font-inter
,而是保留变量引用,交由运行时(浏览器)去解析。
实战应用
虽然 Tailwind 旨在满足你的大部分样式需求,但没有什么可以阻止你在需要时只编写纯 CSS:
@theme inline {
--font-sans: var(--font-inter);
}
这个语法的效果是:让 Tailwind 把这个变量的值原封不动地写进最终的工具类中,而不是先计算它。
编译结果如下:
.font-sans {
font-family: var(--font-inter);
}
这样,当 Tailwind 构建 .font-sans
工具类时,它不会试图提前计算 --font-inter
,而是保留变量引用,交由运行时(浏览器)去解析。
定义主题样式
/* 主题样式 */
@theme inline {
--color-bg: var(--color-bg);
--color-text: var(--color-tx);
}
/* 微信小程序 */
[data-theme='wx'] {
--color-bg: #07aa5c;
--color-tx: #ffffff;
}
/* app */
[data-theme='app'] {
--color-bg: #1a1a1a;
--color-tx: #f5f5f5;
}
设置attr
export const updateRootAttribute = (value) => {
let mode = value || uni.getStorageSync('theme') || 'light'
const isH5 = process.env.UNI_PLATFORM === 'h5'
if (isH5) {
document.documentElement.setAttribute('data-theme', mode)
uni.setStorageSync('theme', mode)
}
}
进行初始化
onShow: function () {
var json = initUrlStr() || {}
this.globalData = json
console.log(json, this.globalData, 'json,页面初始化')
updateRootAttribute(this.globalData.theme || 'wx')
},
页面使用
bg-bg :背景颜色
text-text: 字体颜色
<view
class="w-[700rpx] h-[94rpx] bg-bg m-auto mt-[50rpx] text-text leading-[94rpx] rounded-[48rpx] text-[32rpx]"
@click="submit"
>
同意授权
</view>