UnoCSS 主题系统完全指南:颜色、断点与设计令牌(Airi 项目实战解析)

发布时间:2026/9/10 10:59:50
UnoCSS 主题系统完全指南:颜色、断点与设计令牌(Airi 项目实战解析) UnoCSS 主题系统完全指南颜色、断点与设计令牌Airi 项目实战解析【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airiUnoCSS 的theme配置是一套与 Tailwind CSS / Windi CSS 一脉相承的设计令牌Design Tokens系统负责统一管理颜色、断点、字体、动画等全局样式变量并深度融入 rules、variants、shortcuts 三大核心机制。本文以官方 skill 文档 core-theme.md 为骨架结合 Airi 仓库根目录真实的 uno.config.ts 与各应用子配置完整讲解主题的配置方法、合并语义、断点陷阱与多 preset 差异读完即可在自己的 Vue / Vite 项目中搭建出可维护的主题体系。主题的本质与默认主题深度合并UnoCSS 的主题机制与 Tailwind / Windi 类似配置中的theme对象会与默认主题做深度合并deep merge因此你无需重复声明全部默认值只需覆盖关心的部分。核心入口是一个 uno.config.ts 配置文件UnoCSS 会自动在项目根目录查找uno.config.{js,ts,mjs,mts}或unocss.config.{js,ts,mjs,mts}见 core-config.md。最基本的颜色主题用法如下theme: { colors: { veryCool: #0000ff, // classtext-very-cool brand: { primary: hsl(var(--hue, 217) 78% 51%), // classbg-brand-primary DEFAULT: #942192, // classbg-brand }, }, }这里揭示了两个关键约定叶子节点如veryCool: #0000ff直接映射为工具类后缀text-very-cool、bg-very-cool立即可用嵌套对象如brand通过路径访问子键同时DEFAULT键用于生成不带后缀的bg-brand类。颜色值不仅支持十六进制还可以直接使用 CSS 变量表达式如hsl(var(--hue, 217) 78% 51%)这为运行时动态换肤例如根据用户偏好切换主色相保留了通道。在 rules 中读取主题动态规则的心脏主题的真正价值在于被规则消费。动态规则dynamic rules的函数签名第二参数为上下文对象其中包含themerules: [ [/^text-(.*)$/, ([, c], { theme }) { if (theme.colors[c]) return { color: theme.colors[c] } }], ]这种「正则匹配类名 查表主题」的模式正是 UnoCSS 工具类体系的底层范式。Airi 仓库在 uno.config.ts 中有一个实战范例bg-dotted-[...]规则它通过parseColor解析主题颜色并生成径向渐变点阵背景[/^bg-dotted-\[(.*)\]$/, ([, color], { theme }) { const parsedColor parseColor(color, theme) return { background-image: radial-gradient(circle at 1px 1px, ${colorToString(parsedColor?.cssColor ?? parsedColor?.color ?? color, var(--un-background-opacity))} 1px, transparent 0), --un-background-opacity: parsedColor?.cssColor?.alpha ?? parsedColor?.alpha ?? 1, } }],可以看到parseColor(color, theme)同时接受主题键如primary与任意 CSS 颜色值这正是主题作为「共享色板」在规则层被复用的直接证据。规则层更多语法静态规则、特殊符号、多选择器规则等可参考 core-rules.md。在 variants 中读取主题响应式与伪类的数据源变体variants同样可以在match函数中拿到theme常用于读取theme.breakpoints、theme.colors来实现自定义响应式前缀variants: [ { name: variant-name, match(matcher, { theme }) { // Access theme.breakpoints, theme.colors, etc. }, }, ]变体的工作方式是「逐级剥前缀」hover:m-2被hover:变体匹配后剥离为m-2再交给规则生成.m-2最后变体将选择器改写为.hover\:m-2:hover流程详见 core-variants.md。Airi 的 uno.config.ts 中定义了一个读取 matcher 的presetStoryMockHover预设通过改写 selector 把:hover同时绑定到._hover类用于 Storybook 场景下模拟悬停态——这也是变体机制与主题/选择器配合的典型工程实践。在 shortcuts 中读取主题动态快捷类的查表模式shortcuts 用于把多条工具类组合成语义化类名动态 shortcuts 同样接收带theme的上下文shortcuts: [ [/^badge-(.*)$/, ([, c], { theme }) { if (Object.keys(theme.colors).includes(c)) return bg-${c}4:10 text-${c}5 rounded }], ]上例中bg-${c}4:10的写法利用了 UnoCSS 的颜色透明度语法bg-primary-400/10风格此处4为色阶、10为透明度百分比即「主题色板 透明度修饰符」的组合。shortcuts 在构建期展开、支持引用其他 shortcuts、且与所有变体兼容hover:btn、dark:btn均可用详见 core-shortcuts.md。断点配置覆盖而非合并务必当心断点是响应式设计的基石但 UnoCSS 的breakpoints有一个重要陷阱自定义breakpoints对象会整体覆盖默认值而不是合并。theme: { breakpoints: { sm: 320px, md: 640px, }, }配置后只有sm:和md:两个变体可用默认的lg、xl、2xl全部失效。同理verticalBreakpoints对纵向布局生效方式一致。继承默认断点extendTheme 的正确姿势若希望「在默认断点基础上微调」必须使用extendTheme回调手工展开合并extendTheme: (theme) { return { ...theme, breakpoints: { ...theme.breakpoints, sm: 320px, md: 640px, }, } }断点排序保持单位一致UnoCSS 会对断点按数值大小排序以生成min-width/max-width媒体查询。混用单位会导致排序错误theme: { breakpoints: { sm: 320px, // Dont mix units - convert rem to px // md: 40rem, // Bad md: ${40 * 16}px, // Good lg: 960px, }, }${40 * 16}px即 640px用模板计算保持全部断点统一为px避免排序异常。extendTheme修改或替换合并后的主题extendTheme在默认主题与theme合并完成后执行拿到的是最终主题对象支持两种用法就地修改mutateextendTheme: (theme) { theme.colors.veryCool #0000ff theme.colors.brand { primary: hsl(var(--hue, 217) 78% 51%), } }返回新对象整体替换replaceextendTheme: (theme) { return { ...theme, colors: { ...theme.colors, veryCool: #0000ff, }, } }两种方式各有用武之地mutate 适合在 preset 内部增量注入令牌replace 适合需要过滤/重组键集的场景注意必须展开...theme以免丢失默认令牌。从源码结构看这一机制也是 preset 向配置暴露主题扩展点的官方通道。不同 preset 的主题键差异wind3 与 wind4主题键在不同 preset 中命名存在差异迁移或混用前必须确认。官方对照表如下主题键preset-wind3主题键preset-wind4fontFamilyfontfontSizetext.fontSizelineHeighttext.lineHeight或leadingletterSpacingtext.letterSpacing或trackingborderRadiusradiuseasingeasebreakpointsbreakpointboxShadowshadowtransitionPropertypropertywind3 是「Tailwind CSS v3 / Windi CSS 兼容」的常用预设unocss/preset-uno与unocss/preset-wind已废弃并改名为unocss/preset-wind3wind4 面向 Tailwind v4 风格引入了text.fontSize等嵌套结构与 CSS 变量主题层。若需要极简底座可选用 preset-mini.md其theme内的breakpoints同样是覆盖而非合并语义。常见主题键一览colors— 调色板支持嵌套对象与DEFAULT键breakpoints— 响应式断点覆盖语义verticalBreakpoints对应纵向布局fontFamily— 字体栈fontSize— 字号刻度spacing— 间距刻度borderRadius— 圆角值boxShadow— 阴影定义animation— 动画关键帧与时长Airi 仓库实战一套贯穿全仓的主题配置Airi 是一个 monorepo根目录 uno.config.ts 通过sharedUnoConfig()导出共享配置各应用再以mergeConfigs叠加差异。这套配置是主题系统的绝佳范本。字体族主题多层回退的 fontFamilytheme: { fontFamily: { sans: DM Sans Variant, DM Sans, ui-sans-serif, system-ui, sans-serif, ..., sans-rounded: Comfortaa Variable, Comfortaa, DM Sans, ..., cute: Nunito Variable, Nunito, ChillRoundM, Kiwi Maru, Comfortaa Variable, ..., cutejp: Nunito Variable, Nunito, ChillRoundM, Kiwi Maru, ..., cuteen: Nunito Variable, Nunito, ChillRoundM, Kiwi Maru, ..., }, }见 uno.config.ts这里sans、sans-rounded、cute、cutejp、cuteen组成了面向不同语气可爱/日文/英文的字体令牌配合 packages/font-* 系列自托管字体包如font-chillroundm、font-cjkfonts-allseto、font-xiaolai实现「CSS 变量 多层回退」的字体主题。值得留意的是根配置同时通过presetWebFontsFonts(fontsource | none)在 apps/stage-web/uno.config.ts 中按构建环境切换字体 provider。animation 主题关键帧 时长 缓动三段式animation: { keyframes: { overlayShow: {from{opacity:0;}to{opacity:1;}}, contentShow: {from:{opacity:0;transform:translate(-50%,-48%) scale(0.96);}to:{opacity:1;transform:translate(-50%,-50%) scale(1);}}, slideUpAndFade: {from{opacity:0;transform:translateY(2px)}to{opacity:1;transform:translateY(0)}}, // ... }, durations: { overlayShow: 300ms, contentShow: 150ms, slideUpAndFade: 400ms, }, timingFns: { overlayShow: cubic-bezier(0.16, 1, 0.3, 1), fadeIn: ease-in-out, }, }见 uno.config.ts这套 keyframes / durations / timingFns 结构与官方 wind4 的theme/animate.ts对齐覆盖了弹层overlay/content、滑入滑出slideXxxAndFade、淡入淡出fadeIn/fadeOut等 UI 过渡是「以主题令牌驱动动画」的最佳实践。预设注入的主题色板presetChromaticAiri 通过presetChromatic预设动态生成主题色阶presetChromatic({ baseHue: 220.44, colors: { primary: 0, complementary: 180, }, }) as Preset,见 uno.config.ts它基于色相基准baseHue: 220.44自动推导出primary同相与complementary补色 180°的完整色阶。与之配套的safelistAllPrimaryBackgrounds()uno.config.ts会把bg-primary及 50–950 各色阶、5–100 各透明度的组合全部写入safelist确保动态拼接的类名不会被按需提取漏掉[undefined, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950].map((shade) { const prefix shade ? bg-primary-${shade} : bg-primary return [prefix, ...[5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100].map(opacity ${prefix}/${opacity})] }).flat()这正是「主题色板 safelist」在真实大型应用中的典型配合主题负责语义化颜色safelist 保证运行时拼接的类名稳定产出。子应用覆盖mergeConfigs 按需扩展apps/stage-web/uno.config.ts 通过mergeConfigs([sharedUnoConfig(), {...}])在共享主题之上追加presetWebFonts并显式配置timeouts.warning/failure规避 CI 网络超时与transition-colors-none等专属规则。这种「根配置定主题基调 子应用按需覆盖」的分层模式使整个 monorepo 的颜色、字体、动画令牌保持单一事实来源。小结UnoCSS 主题系统的核心可以归纳为四句话theme与默认主题深度合并breakpoints覆盖不合并想继承就用extendTheme展开rules / variants / shortcuts 都能通过上下文{ theme }消费令牌不同 preset 的主题键命名不同wind3 与 wind4 需对照迁移。Airi 仓库的 uno.config.ts 为这三者提供了完整的工业化范例——从多字体回退、动画三段式令牌到预设动态色阶与 safelist 联动值得作为你搭建自己主题系统的直接参考。如果你想进一步深入建议按此顺序阅读官方 skill 文档core-config.md配置项全览、core-rules.md规则消费主题、core-shortcuts.md快捷类消费主题、core-variants.md变体消费主题再对照 preset-wind3.md 与 preset-mini.md 理解主题键在预设间的差异。【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考