- 前端
- AI 技能
【免费下载链接】basic
⭐⭐⭐⭐⭐ 面向 AI 编程的管理系统框架,兼容PC、移动端。AI-oriented management system framework, compatible with PC and mobile device.
本文档讲解 Fantastic-admin(本仓库中由packages/themes/index.ts导出的lightTheme/darkTheme定义的)主题体系的核心骨架:它由shadcn 标准 token与框架专属--g-*token两类 CSS 变量组成,前者控制组件级颜色,后者控制布局区域(头部、主侧边栏、次侧边栏、标签栏、工具栏)的配色。读完本文,你将掌握这两类变量的完整清单与取值规范、明暗两套主题在 5 个关键维度上的差异设计、完整暗色--g-*模板,以及它们如何通过 UnoCSS 预处理器注入页面并被布局组件实际消费的底层链路,从而能够自行创建和定制符合规范的主题配色。
一、主题变量的两类构成
Fantastic-admin 的主题不是单一的颜色变量表,而是由两类职责清晰的变量共同组成:
- shadcn 标准 token— 通用设计系统变量,控制按钮、卡片、输入框、弹出层等组件的颜色语义,与社区 shadcn/ui 生态保持兼容。
- 框架专属 token(
--g-*)— 控制布局区域颜色,例如头部(Header)、主导航(MainSidebar)、次导航(SubSidebar)、标签栏(Tabbar)、工具栏(Toolbar)、主内容区(MainArea),是 Fantastic-admin 对通用 token 的布局级扩展。
这种分层设计的价值在于:shadcn 标准 token 负责"组件语义"(什么状态该用什么色),--g-*负责"区域归属"(哪个布局区域引用哪个语义色),二者通过oklch(var(--xxx))这种引用式赋值串联起来,使得改一个语义色即可联动整个布局。
源码佐证:主题定义与注入位置
- 主题定义文件:packages/themes/index.ts,以
as const导出lightTheme与darkTheme,跨所有应用共享; - 注入实现:uno.config.ts 中名为
unocss-preset-shadcn的 UnoCSS preset,通过entriesToCss(Object.entries(lightTheme))把变量写入:root,通过entriesToCss(Object.entries(darkTheme))写入.dark,并在configDeps中声明对packages/themes/index.ts的依赖,使主题文件变更可被构建工具自动追踪。
// uno.config.ts 中注入主题变量的核心片段 toArray(':root').map(root => `${root}{color-scheme:light;${entriesToCss(Object.entries(lightTheme))}}`).join(''), toArray('.dark').map(root => `${root}{color-scheme:dark;${entriesToCss(Object.entries(darkTheme))}}`).join(''),二、shadcn 标准 Token 详解
shadcn 标准 token 的取值格式为'L C H'——OKLCH 三个数值,用空格分隔,不含oklch()包裹(例如'1 0 0'即纯白oklch(1 0 0))。
| 变量 | 作用 |
|---|---|
--background | 页面主背景色 |
--foreground | 主文字颜色 |
--card | 卡片背景色(通常同 background) |
--card-foreground | 卡片文字颜色 |
--popover | 弹出层背景色 |
--popover-foreground | 弹出层文字颜色 |
--primary | 主色调(按钮、高亮、激活状态) |
--primary-foreground | 主色上的文字颜色 |
--secondary | 次要色(次要按钮、标签背景) |
--secondary-foreground | 次要色上的文字颜色 |
--muted | 静音色(禁用状态、次要背景) |
--muted-foreground | 静音色上的文字颜色 |
--accent | 强调色(hover 状态背景) |
--accent-foreground | 强调色上的文字颜色 |
--destructive | 危险/错误色(删除、警告) |
--border | 边框颜色 |
--input | 输入框边框颜色 |
--ring | 焦点环颜色(通常同 primary) |
从 uno.config.ts 可以看到,这些 token 被映射为 UnoCSS 主题色板(background、foreground、primary、secondary、muted、accent、destructive、border、input、ring等),组件中可直接使用bg-primary、text-muted-foreground这类工具类,其底层色值即oklch(var(--xxx))。
默认色值参考(当前仓库实际值)
明色主题(packages/themes/index.ts):
'--background': '1 0 0', // oklch(1 0 0) 纯白 '--foreground': '0.145 0 0', // 近黑文字 '--card': '1 0 0', '--card-foreground': '0.145 0 0', '--popover': '1 0 0', '--popover-foreground': '0.145 0 0', '--primary': '0.205 0 0', // 深色主按钮 '--primary-foreground': '0.985 0 0', '--secondary': '0.97 0 0', '--secondary-foreground': '0.205 0 0', '--muted': '0.97 0 0', '--muted-foreground': '0.556 0 0', '--accent': '0.97 0 0', '--accent-foreground': '0.205 0 0', '--destructive': '0.577 0.245 27.325', // 红色系,通常保持不变 '--border': '0.922 0 0', '--input': '0.922 0 0', '--ring': '0.708 0 0',三、框架专属 Token(--g-*)
框架专属 token 的取值格式为'oklch(L C H)'或'oklch(var(--xxx))'——含oklch()包裹,且通常直接引用 shadcn 标准 token,形成"语义色 → 区域色"的引用链。
| 变量 | 作用 |
|---|---|
--g-main-area-bg | 主内容区域背景 |
--g-header-bg | 顶部背景 |
--g-header-color | 顶部文字颜色 |
--g-header-menu-color | 顶部导航菜单项文字颜色 |
--g-header-menu-hover-bg | 顶部导航菜单项 hover 背景 |
--g-header-menu-hover-color | 顶部导航菜单项 hover 文字颜色 |
--g-header-menu-active-bg | 顶部导航菜单项激活背景 |
--g-header-menu-active-color | 顶部导航菜单项激活文字颜色 |
--g-main-sidebar-bg | 主侧边栏背景 |
--g-main-sidebar-menu-color | 主侧边栏导航菜单文字颜色 |
--g-main-sidebar-menu-hover-bg | 主侧边栏导航菜单 hover 背景 |
--g-main-sidebar-menu-hover-color | 主侧边栏导航菜单 hover 文字颜色 |
--g-main-sidebar-menu-active-bg | 主侧边栏导航菜单激活背景 |
--g-main-sidebar-menu-active-color | 主侧边栏导航菜单激活文字颜色 |
--g-sub-sidebar-bg | 次侧边栏背景 |
--g-sub-sidebar-menu-color | 次侧边栏导航菜单文字颜色 |
--g-sub-sidebar-menu-hover-bg | 次侧边栏导航菜单 hover 背景 |
--g-sub-sidebar-menu-hover-color | 次侧边栏导航菜单 hover 文字颜色 |
--g-sub-sidebar-menu-active-bg | 次侧边栏导航菜单激活背景 |
--g-sub-sidebar-menu-active-color | 次侧边栏导航菜单激活文字颜色 |
--g-tabbar-bg | 标签栏背景 |
--g-tabbar-tab-color | 标签项文字颜色 |
--g-tabbar-tab-hover-bg | 标签项 hover 背景 |
--g-tabbar-tab-hover-color | 标签项 hover 文字颜色 |
--g-tabbar-tab-active-bg | 标签项激活背景 |
--g-tabbar-tab-active-color | 标签项激活文字颜色 |
--g-toolbar-bg | 工具栏背景 |
布局组件如何消费这些变量
从源码结构看,每个布局区域组件都直接以 CSS 变量声明其样式,主题换色无需改动组件逻辑:
- 主内容区:apps/core/src/layouts/index.vue 中
background-color: var(--g-main-area-bg); - 头部:apps/core/src/layouts/components/Header/index.vue 中
background-color: var(--g-header-bg),菜单项通过text-[var(--g-header-menu-color)]、hover:(text-[var(--g-header-menu-hover-color)] bg-[var(--g-header-menu-hover-bg)])、bg-[var(--g-header-menu-active-bg)]等工具类引用对应状态变量; - 主侧边栏:apps/core/src/layouts/components/MainSidebar/index.vue 中声明
color: var(--g-main-sidebar-menu-color)、background-color: var(--g-main-sidebar-bg)及各 hover/active 状态; - 次侧边栏:apps/core/src/layouts/components/Menu/item.vue 中通过
text-[var(--g-sub-sidebar-menu-color)]、bg-[var(--g-sub-sidebar-menu-active-bg)]消费次导航变量; - 标签栏:apps/core/src/layouts/components/Topbar/Tabbar/index.vue 中
background-color: var(--g-tabbar-bg); - 工具栏:apps/core/src/layouts/components/Topbar/Toolbar/index.vue 中
bg-[var(--g-toolbar-bg)]。
四、明色与暗色的 5 处关键差异
明色与暗色主题除了色值深浅不同外,在--g-*变量的取值策略上存在 5 处刻意设计的差异。理解这些差异是手写暗色主题模板的前提。
差异一:菜单激活状态
明色激活态使用primary(高对比、品牌感),暗色激活态改用accent(更柔和的明度差,避免暗色下高亮过曝):
// 明色 '--g-header-menu-active-bg': 'oklch(var(--primary))', '--g-header-menu-active-color': 'oklch(var(--primary-foreground))', // 暗色 '--g-header-menu-active-bg': 'oklch(var(--accent))', '--g-header-menu-active-color': 'oklch(var(--accent-foreground))',同样适用于--g-main-sidebar-menu-active-*和--g-sub-sidebar-menu-active-*,即主导航与次导航菜单的激活态遵循同一规则。
差异二:主内容区背景
明色下主内容区背景略深于页面背景,形成内容区与背景的层次感;暗色下则与背景相同,避免暗色界面层次过多造成视觉负担:
// 明色:略深于背景,形成层次感 '--g-main-area-bg': 'oklch(0.9612 0 0)', // 暗色:与背景相同,避免过多层次 '--g-main-area-bg': 'oklch(var(--background))',差异三:标签栏 hover 背景
// 明色 '--g-tabbar-tab-hover-bg': 'oklch(var(--border))', // 暗色 '--g-tabbar-tab-hover-bg': 'oklch(var(--accent) / 50%)',暗色使用accent并叠加 50% 透明度,让 hover 反馈更克制。
差异四:标签栏激活背景
// 明色 '--g-tabbar-tab-active-bg': 'oklch(var(--background))', // 暗色 '--g-tabbar-tab-active-bg': 'oklch(var(--secondary))',差异五:菜单颜色引用
菜单项默认文字颜色,明色引用accent-foreground,暗色引用muted-foreground——暗色下文字弱化,突出可读层级:
// 明色:使用 accent-foreground '--g-header-menu-color': 'oklch(var(--accent-foreground))', '--g-header-menu-hover-color': 'oklch(var(--accent-foreground))', // 暗色:使用 muted-foreground '--g-header-menu-color': 'oklch(var(--muted-foreground))', '--g-header-menu-hover-color': 'oklch(var(--muted-foreground))',五、完整暗色--g-*模板
以下是可直接复制使用的完整暗色--g-*变量模板(与 packages/themes/index.ts 中darkTheme的实现一致):
dark: { // shadcn token ... '--g-main-area-bg': 'oklch(var(--background))', '--g-header-bg': 'oklch(var(--background))', '--g-header-color': 'oklch(var(--foreground))', '--g-header-menu-color': 'oklch(var(--muted-foreground))', '--g-header-menu-hover-bg': 'oklch(var(--muted))', '--g-header-menu-hover-color': 'oklch(var(--muted-foreground))', '--g-header-menu-active-bg': 'oklch(var(--accent))', '--g-header-menu-active-color': 'oklch(var(--accent-foreground))', '--g-main-sidebar-bg': 'oklch(var(--background))', '--g-main-sidebar-menu-color': 'oklch(var(--muted-foreground))', '--g-main-sidebar-menu-hover-bg': 'oklch(var(--muted))', '--g-main-sidebar-menu-hover-color': 'oklch(var(--muted-foreground))', '--g-main-sidebar-menu-active-bg': 'oklch(var(--accent))', '--g-main-sidebar-menu-active-color': 'oklch(var(--accent-foreground))', '--g-sub-sidebar-bg': 'oklch(var(--background))', '--g-sub-sidebar-menu-color': 'oklch(var(--muted-foreground))', '--g-sub-sidebar-menu-hover-bg': 'oklch(var(--muted))', '--g-sub-sidebar-menu-hover-color': 'oklch(var(--muted-foreground))', '--g-sub-sidebar-menu-active-bg': 'oklch(var(--accent))', '--g-sub-sidebar-menu-active-color': 'oklch(var(--accent-foreground))', '--g-tabbar-bg': 'oklch(var(--background))', '--g-tabbar-tab-color': 'oklch(var(--accent-foreground) / 50%)', '--g-tabbar-tab-hover-bg': 'oklch(var(--accent) / 50%)', '--g-tabbar-tab-hover-color': 'oklch(var(--accent-foreground) / 50%)', '--g-tabbar-tab-active-bg': 'oklch(var(--accent))', '--g-tabbar-tab-active-color': 'oklch(var(--foreground))', '--g-toolbar-bg': 'oklch(var(--background))', },对照第 4 节可以逐条验证:暗色模板全部采用accent激活、muted-foreground菜单文字、background同源的主内容区,并且标签栏 hover/激活使用带透明度的accent系取值。
六、如何基于本结构创建自定义主题
结合 skills/fa-theme-customizer/SKILL.md 描述的工作流,自定义主题的实操路径如下:
- 确认设计风格:若没有明确的品牌色,可参考 skills/fa-theme-customizer/references/design-styles.md 中收录的 20+ 种设计风格配色(吉卜力、赛博朋克、莫兰迪、北欧极简、瑞士国际主义等),或 tweakcn 社区主题的 shadcn CSS 变量。
- 生成 OKLCH 色值:框架使用 OKLCH 色彩空间,shadcn token 格式为
L C H(不含oklch()包裹)。转换规则参考:- 明色背景:
1 0 0(纯白)或接近白色的暖/冷色调; - 暗色背景:
0.141 0.005 285.823(默认深灰)或更深的色调; - 主色(primary):明色通常比暗色亮度(L 值)高 0.05~0.1。
- 明色背景:
- 替换主题文件:在 packages/themes/index.ts 中替换
lightTheme与darkTheme,格式严格遵循第 2、3 节的变量清单与第 5 节的暗色模板;类型由as const自动推断,无需手动更新类型定义。 - 始终同时生成明色与暗色两套主题,并套用第 4 节的 5 处明暗差异规则。
主题开关的运行时配置
主题的明暗切换由设置系统驱动:packages/settings/src/types.ts 中ThemeSettings.colorScheme支持'light' | 'dark' | ''(''表示跟随系统),另有radius(圆角系数,0~1,默认 0.5)与colorAmblyopia(色弱模式)两个主题相关配置;默认值定义在 packages/settings/src/default.ts(colorScheme: 'light'、radius: 0.5、colorAmblyopia: false)。.dark类名的挂载与:root的切换,即由该配置联动uno.config.ts中的预置 CSS 生效。
七、小结
Fantastic-admin 的主题体系用"shadcn 标准 token + 框架专属--g-*token"两层结构,实现了组件语义色与布局区域色的解耦:shadcn token 以裸L C H数值定义语义,--g-*以oklch(var(--xxx))引用语义并分发到头部、主/次侧边栏、标签栏、工具栏等区域;明暗两套主题在菜单激活、主内容区背景、标签栏 hover/激活、菜单颜色引用 5 个维度上采用差异化取值策略。掌握 packages/themes/index.ts 中的变量结构,即可为 Fantastic-admin 创建符合规范、明暗自洽的全新主题。
- 前端
- AI 技能
【免费下载链接】basic
⭐⭐⭐⭐⭐ 面向 AI 编程的管理系统框架,兼容PC、移动端。AI-oriented management system framework, compatible with PC and mobile device.
相关推荐
LeetCode-Book 最小栈(LCR 147)双栈解法全解析:getMin() O(1) 实现的原理、函数设计与三语言代码
LeetCode Book 最小栈(LCR 147)双栈解法全解析:getMin O 1 实现的原理、函数设计与三语言代码 导读 本文以 LeetCode Bo
前端AI 技能从0到1定制Water.css主题:CSS变量全攻略
从0到1定制Water.css主题:CSS变量全攻略 你是否曾为网站样式调整耗费数小时?想让页面既美观又保持简洁?本文将通过CSS变量系统,教你30分钟内定制专
前端如何快速掌握TileMapDual:打造精美六边形地图的完整教程
如何快速掌握TileMapDual:打造精美六边形地图的完整教程 想要在Godot中创建令人惊艳的六边形蜂窝地图吗?TileMapDual这款强大的双网格瓦片系
游戏开发开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考