Skip to content

参考:vanilla-extract API 速查

基于 vanilla-extract 1.21.1 · 核于 2026-07

速查

  • 定位:TypeScript-first 零运行时样式;.css.ts 构建期出静态 CSS + 作用域类名。核心包 @vanilla-extract/css(MIT)。
  • 核心链路:写 .css.tsstyle()/createTheme() 等声明 → 打包器插件构建期抽取 → import 类名用。
  • 样式style / globalStyle / styleVariants / keyframes+globalKeyframes / fontFace+globalFontFace / createVar+fallbackVar / createContainer / layer+globalLayer
  • 主题createTheme[class, vars])/ createThemeContract / createGlobalTheme / createGlobalThemeContract / assignVars
  • 生态recipesrecipe()+RecipeVariantssprinklesdefineProperties+createSprinklesdynamicassignInlineVars+setElementVars
  • 选择器:简单伪类写顶层;复杂选择器进 selectors& 须在主语位);后代样式用 globalStyle;循环依赖用 getter。
  • 值规则:camelCase;数字补 px(无单位属性除外);前缀 PascalCase;回退用数组;令牌是字符串。
  • 动态.css.ts 静态求值 → 运行时用 CSS 变量占位 + assignInlineVars
  • 集成:Vite/webpack/esbuild/Next/Rollup/Parcel/Gatsby 各插件,Astro/Remix 走 Vite;Vite identifiersshort/debug/函数。

一、核心 API(@vanilla-extract/css)

API作用返回
style(obj | obj[])定义一条作用域样式规则类名字符串
globalStyle(selector, styles)定义全局(不作用域化)规则
styleVariants(map[, mapper])一组命名样式{ 键: 类名 }
createVar([property])造 CSS 变量引用(可选 @property 类型化)变量引用
fallbackVar(v, ...fallbacks)变量回退值变量表达式
keyframes(steps) / globalKeyframes(name, steps)定义动画作用域/全局动画名
fontFace(cfg | cfg[]) / globalFontFace(name, cfg)定义 @font-face作用域/全局字体名
createContainer()造作用域容器名(配 @container容器名
layer([opts]) / globalLayer(name)造级联层引用(配 @layer层引用/名

二、主题 API

API作用生成 CSS?返回
createTheme(tokens)主题 class + 令牌契约[themeClass, vars]
createTheme(vars, tokens)复用契约、新 class 赋新值(多主题)themeClass
createThemeContract(shape)契约先行、不产 CSSvars
createGlobalTheme(selector, tokens)令牌赋到全局选择器vars
createGlobalTheme(selector, vars, tokens)全局实现既有契约
createGlobalThemeContract(map, mapFn)契约映射到全局变量名vars
assignVars(contract, values)在 style/选择器/媒体查询里整组赋值—(在宿主 style 内)vars 赋值对象

三、生态子包

关键 API一句话
@vanilla-extract/recipesrecipe({ base, variants, compoundVariants, defaultVariants })RecipeVariants<T>多变体组件样式(类 cva/Stitches),返回可调用函数
@vanilla-extract/sprinklesdefineProperties(...)createSprinkles(...)sprinkles(...)零运行时、类型安全的原子化工具类(自建 Tailwind)
@vanilla-extract/dynamicassignInlineVars(vars, values)setElementVars(el, vars, values)< 1kB 运行时改内联 CSS 变量值,动态主题不新增 CSS

四、选择器与 at-rule 速记

需求写法
简单伪类顶层键 ':hover': {...}
复杂选择器(针对自身)selectors: { '&:not(:first-child)': {...} }& 在主语位
引用别的 classselectors: { [`${other} &`]: {} }
给后代上样式globalStyle(`${parent} a`, {}) (不能写在 selectors)
循环选择器依赖get selectors() { return {...} } getter
媒体查询'@media': { 'screen and (min-width: 768px)': {...} }
特性查询'@supports': { '(display: grid)': {...} }
容器查询createContainer() + containerName + '@container': {...}
级联层layer() + '@layer': { [层]: {...} }
属性回退overflow: ['auto', 'overlay']
样式组合style([a, b, { ':hover': {...} }])

五、选型对比:CSS-in-JS / 样式方案

维度vanilla-extractStyleXPanda CSSCSS Modulesstyled-components / Emotion
运行时零运行时零运行时零运行时零运行时运行时注入
样式生成构建期静态 CSS构建期原子 CSS(Babel)构建期 codegen构建期作用域 CSS运行时拼接
写法独立 .css.ts(TS 对象)组件旁 JS 对象(就地共置)配置 + style props/patterns标准 .css 文件标签模板
心智像带类型的 Sass原子化 + 合并后者胜设计系统 codegen默认局部的 CSS组件即样式
类型安全令牌✅ 主题契约defineVars✅ tokens❌(需额外 d.ts)一般无
原子化靠 sprinkles✅ 内建✅ 内建
SSR/RSC友好友好友好友好需样式收集/注水
典型场景设计系统 + 组件库,重类型安全Meta 系大型 React 应用设计系统优先、想要 style props只想要作用域的标准 CSS快速迭代、重运行时动态

选型速记:想要「TS 写样式 + 类型安全令牌 + 独立样式文件 + 零运行时」→ vanilla-extract;要「原子化 + 就地共置 + 可预测优先级」→ StyleX;要「配置驱动的设计系统 + style props」→ Panda CSS;只想给标准 CSS 加作用域 → CSS Modules;要「运行时按 props 大量派生样式、不在意运行时开销」→ Emotion(但 SSR/RSC 场景应优先零运行时方案)。

六、常见坑

现象原因 / 解法
.css.ts 里读 props/window 报错或值不对构建期无运行时数据 → 用 createVar 占位 + assignInlineVars
selectors 里写 '& .child' 不生效/报错目标必须是当前元素 → 后代用 globalStyle
两个 class 选择器互相引用报「未初始化」循环依赖 → 用 get selectors() getter
多主题切换后组件读到的值没变createTheme(vars, {...}) 复用契约,别重新 createTheme({...})
实现契约时提示缺值契约要求完整赋值,补齐所有令牌
Next 里第三方 ve 库样式不生效把该库加进 transpilePackages
生产类名太长/太短不便调试Vite identifiers: 'debug' / 'short' 切换
数字没补 px 或补错无单位属性(flexGrow/opacity 等)本就不补 px

七、权威链接