admin 管理员组文章数量: 1184232
vanilla-extract的主题系统API:创建与使用主题
vanilla-extract是一个零运行时的TypeScript样式解决方案(Zero-runtime Stylesheets-in-TypeScript),其主题系统基于CSS变量(CSS Variables)构建,通过类型安全的API实现主题的创建、管理和切换。本文将详细介绍vanilla-extract主题系统的核心API,包括主题契约(Theme Contract)的定义、主题实现以及动态主题切换等功能,并结合实际代码示例展示如何在项目中应用。
主题系统核心概念
vanilla-extract的主题系统主要围绕以下两个核心概念构建:
- 主题契约(Theme Contract) :定义主题中包含的变量结构,如颜色、字体、间距等,类似于接口(Interface)的作用,确保所有主题实现遵循统一的变量规范。
- 主题实现(Theme Implementation) :基于主题契约定义具体的变量值,生成对应的CSS类名,用于在页面中应用主题。
主题系统的核心API包括
createThemeContract
和
createTheme
,分别用于创建主题契约和实现主题。此外,
@vanilla-extract/dynamic
包提供了
assignInlineVars
方法,支持在运行时动态设置主题变量。
创建主题契约:
createThemeContract
createThemeContract
用于定义主题契约,即主题中包含的变量结构。它不会生成任何CSS代码,仅用于类型定义和变量名生成。
基本用法
// themes.css.ts
import { createThemeContract } from '@vanilla-extract/css';
export const vars = createThemeContract({
color: {
brand: null,
background: null,
text: null
},
font: {
body: null,
heading: null
},
space: {
1: null, // 4px
2: null, // 8px
3: null // 12px
}
});
在上述代码中,
createThemeContract
接受一个对象作为参数,该对象定义了主题变量的结构。对象的值可以是
null
、空字符串或任何占位值,因为这些值会被忽略,仅用于类型推断。定义完成后,
vars
将包含与输入结构一致的变量访问器,例如
vars.color.brand
对应CSS变量
var(--color-brand__xxx)
(其中
xxx
为vanilla-extract自动生成的哈希值,确保变量名唯一)。
类型安全
createThemeContract
会根据输入的结构生成对应的TypeScript类型,确保后续的主题实现必须包含所有定义的变量,否则会产生类型错误。这为大型项目中的主题维护提供了类型保障。
实现主题:
createTheme
createTheme
用于基于主题契约实现具体的主题。它接受主题契约和主题变量值作为参数,生成对应的CSS类名,该类名包含了所有主题变量的CSS定义。
基本用法
// lightTheme.css.ts
import { createTheme } from '@vanilla-extract/css';
import { vars } from './themes.css.ts';
export const lightThemeClass = createTheme(vars, {
color: {
brand: '#0070f3',
background: '#ffffff',
text: '#333333'
},
font: {
body: 'system-ui, sans-serif',
heading: 'Georgia, serif'
},
space: {
1: '4px',
2: '8px',
3: '12px'
}
});
在上述代码中,
createTheme
接受
vars
(主题契约)和一个对象(主题变量值)作为参数,生成
lightThemeClass
CSS类名。该类名对应的CSS代码如下(简化版):
.lightThemeClass__xxx {
--color-brand__xxx: #0070f3;
--color-background__xxx: #ffffff;
--color-text__xxx: #333333;
--font-body__xxx: system-ui, sans-serif;
--font-heading__xxx: Georgia, serif;
--space-1__xxx: 4px;
--space-2__xxx: 8px;
--space-3__xxx: 12px;
}
创建主题变体
可以基于同一个主题契约创建多个主题变体,例如深色主题:
// darkTheme.css.ts
import { createTheme } from '@vanilla-extract/css';
import { vars } from './themes.css.ts';
export const darkThemeClass = createTheme(vars, {
color: {
brand: '#61dafb',
background: '#1a1a1a',
text: '#ffffff'
},
font: {
body: 'system-ui, sans-serif',
heading: 'Georgia, serif'
},
space: {
1: '4px',
2: '8px',
3: '12px'
}
});
通过这种方式,可以轻松创建多个主题变体,且所有主题变体都遵循相同的主题契约,确保类型安全。
直接创建主题(不使用契约)
createTheme
还支持不通过
createThemeContract
,直接创建主题契约和主题实现。这种方式会同时生成主题契约和对应的CSS类名,但可能导致主题代码无法拆分(所有主题变体必须依赖原始主题)。
// theme.css.ts
import { createTheme } from '@vanilla-extract/css';
export const [themeClass, vars] = createTheme({
color: {
brand: 'blue'
},
font: {
body: 'arial'
}
});
在上述代码中,
createTheme
返回一个元组,包含主题类名(
themeClass
)和主题契约(
vars
)。这种方式适用于简单的主题场景,但对于需要代码拆分的大型项目,建议使用
createThemeContract
单独定义主题契约。
应用主题
创建主题后,可以通过将主题类名应用到HTML元素上来激活主题。
静态主题切换
// App.tsx
import { lightThemeClass } from './lightTheme.css.ts';
import { darkThemeClass } from './darkTheme.css.ts';
function App() {
const isDarkMode = true; // 根据实际逻辑切换
return (
<html className={isDarkMode ? darkThemeClass : lightThemeClass}>
<body>
<h1>Hello, vanilla-extract!</h1>
</body>
</html>
);
}
在上述代码中,通过将
lightThemeClass
或
darkThemeClass
应用到
<html>
元素,实现了主题的静态切换。所有使用
vars
中变量的样式都会自动应用当前主题的变量值。
组件中使用主题变量
在组件样式中,可以直接使用主题契约中的变量:
// Button.css.ts
import { style } from '@vanilla-extract/css';
import { vars } from './themes.css.ts';
export const button = style({
backgroundColor: vars.color.brand,
color: vars.color.text,
padding: vars.space[2],
fontFamily: vars.font.body,
borderRadius: '4px'
});
生成的CSS代码如下:
.Button_button__xxx {
background-color: var(--color-brand__xxx);
color: var(--color-text__xxx);
padding: var(--space-2__xxx);
font-family: var(--font-body__xxx);
border-radius: 4px;
}
动态主题:
assignInlineVars
@vanilla-extract/dynamic
包提供的
assignInlineVars
方法支持在运行时动态设置主题变量,适用于主题变量值需要从后端获取或用户自定义的场景。
// DynamicTheme.tsx
import { assignInlineVars } from '@vanilla-extract/dynamic';
import { vars } from './themes.css.ts';
function DynamicTheme({ brandColor, textColor }) {
return (
<div
style={assignInlineVars(vars, {
color: {
brand: brandColor,
text: textColor
}
})}
>
<p>Dynamic theme content</p>
</div>
);
}
// 使用
<DynamicTheme brandColor="#ff0000" textColor="#ffffff" />
assignInlineVars
接受主题契约和变量值作为参数,返回一个包含CSS变量定义的对象,可直接作为
style
属性应用到元素上。这种方式不会生成额外的CSS类名,而是通过内联样式动态设置CSS变量。
响应式主题
vanilla-extract支持在媒体查询中使用
assignVars
方法,实现响应式主题切换。
// responsiveTheme.css.ts
import { style, assignVars } from '@vanilla-extract/css';
import { vars } from './themes.css.ts';
export const responsiveTheme = style({
vars: assignVars(vars, {
color: {
backgroundColor: 'pink',
text: 'purple'
}
}),
'@media': {
'screen and (min-width: 768px)': {
vars: assignVars(vars.color, {
backgroundColor: 'purple',
text: 'pink'
})
}
}
});
在上述代码中,
assignVars
用于设置主题变量值,结合媒体查询可以实现不同屏幕尺寸下的主题切换。
主题系统示例:
fixtures/themed
vanilla-extract的官方示例
fixtures/themed
展示了主题系统的完整应用。该示例定义了全局主题契约、多个主题实现以及响应式主题切换。
主题契约与实现
// fixtures/themed/src/themes.css.ts
import {
createGlobalTheme,
createTheme,
assignVars,
style,
layer,
} from '@vanilla-extract/css';
export const theme = style({});
// 全局主题契约
export const vars = createGlobalTheme(`:root, ${theme}`, {
colors: {
backgroundColor: 'blue',
text: 'white',
},
space: {
1: '4px',
2: '8px',
3: '12px',
},
});
// 主题变体
export const altTheme = createTheme(vars, {
colors: {
backgroundColor: 'green',
text: 'white',
},
space: {
1: '8px',
2: '12px',
3: '16px',
},
});
// 响应式主题
export const responsiveTheme = style({
vars: assignVars(vars, {
colors: {
backgroundColor: 'pink',
text: 'purple',
},
space: {
1: '6px',
2: '12px',
3: '18px',
},
}),
'@media': {
'screen and (min-width: 768px)': {
vars: assignVars(vars.colors, {
backgroundColor: 'purple',
text: 'pink',
}),
},
},
});
该示例使用
createGlobalTheme
定义了全局主题契约,将主题变量应用到
:root
和
.theme
类上,支持全局主题和局部主题切换。同时,定义了
altTheme
主题变体和
responsiveTheme
响应式主题。
总结
vanilla-extract的主题系统通过
createThemeContract
和
createTheme
提供了类型安全的主题定义和实现方式,支持静态主题切换、动态主题设置和响应式主题等多种场景。其核心优势在于:
- 类型安全 :通过TypeScript确保主题变量的结构一致性,减少运行时错误。
- 零运行时 :主题变量在构建时生成对应的CSS类名和CSS变量,无运行时开销。
-
代码拆分
:通过
createThemeContract单独定义主题契约,支持主题代码的拆分和懒加载。 - 灵活性 :支持静态主题切换、动态主题设置和响应式主题等多种使用场景。
通过合理使用主题系统API,可以构建可维护、可扩展的样式系统,提升大型前端项目的开发效率和代码质量。
官方文档: 主题契约API: 主题实现API: 示例代码:
版权声明:本文标题:Vanilla Extract揭秘:轻松创造与使用风格化的主题 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1770648230a3536042.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论