ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

vue-vben-admin 主题定制完全指南:CSS 变量体系、内置主题与品牌色配置

vue-vben-admin 主题定制完全指南:CSS 变量体系、内置主题与品牌色配置 vue-vben-admin 主题定制完全指南CSS 变量体系、内置主题与品牌色配置【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin导读本文基于 vue-vben-admin 官方文档的《主题》章节系统讲解这套基于 shadcn-vue 中的真实实现代码做进一步验证。主题系统总览CSS 变量 Tailwind 实用类框架的主题能力建立在 shadcn-vue 与 Tailwind CSS 之上二者的结合点是「语义化的 CSS 变量」所有颜色、圆角、字体大小都以--xxx形式的 CSS 变量定义Tailwind 实用类再通过hsl(var(--xxx))引用这些变量。因此你可以选择直接使用 CSS 变量也可以使用 Tailwind 实用程序类进行主题设置二者最终都落到同一组变量上。颜色遵循一套简单而统一的命名约定background变量用于组件的背景颜色foreground变量用于文本颜色。例如div classbg-background text-foreground /这行代码中的bg-background与text-foreground会分别解析为hsl(var(--background))与hsl(var(--foreground))。以此类推大多数组件都按照「xxxxxx-foreground」成对出现的方式组织变量。例如 Button 组件的background为hsl(var(--primary))其foreground为hsl(var(--primary-foreground))。注意CSS 变量内的颜色必须使用hsl格式如0 0% 100%不需要加hsl()包裹也不能带逗号分隔。默认主题完整 CSS 变量列表了解所有可用的变量是自定义主题的前提。下面分别给出默认主题浅色与黑暗模式下的完整变量清单。默认主题浅色变量:root { --font-family: -apple-system, blinkmacsystemfont, Segoe UI, roboto, Helvetica Neue, arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; /* Default background color of body /...etc */ --background: 0 0% 100%; /* 主体区域背景色 */ --background-deep: 216 20.11% 95.47%; --foreground: 210 6% 21%; /* Background color for Card / */ --card: 0 0% 100%; --card-foreground: 222.2 84% 4.9%; /* Background color for popovers such as DropdownMenu /, HoverCard /, Popover / */ --popover: 0 0% 100%; --popover-foreground: 222.2 84% 4.9%; /* Muted backgrounds such as TabsList /, Skeleton / and Switch / */ --muted: 210 40% 96.1%; --muted-foreground: 215.4 16.3% 46.9%; /* 主题颜色 */ --primary: 212 100% 45%; --primary-foreground: 0 0% 98%; /* Used for destructive actions such as Button variantdestructive */ --destructive: 0 78% 68%; --destructive-foreground: 0 0% 98%; /* Used for success actions such as message */ --success: 144 57% 58%; --success-foreground: 0 0% 98%; /* Used for warning actions such as message */ --warning: 42 84% 61%; --warning-foreground: 0 0% 98%; /* Secondary colors for Button / */ --secondary: 240 5% 96%; --secondary-foreground: 240 6% 10%; /* Used for accents such as hover effects on DropdownMenuItem, SelectItem...etc */ --accent: 240 5% 96%; --accent-hover: 200deg 10% 90%; --accent-foreground: 240 6% 10%; /* Darker color */ --heavy: 192deg 9.43% 89.61%; --heavy-foreground: var(--accent-foreground); /* Default border color */ --border: 240 5.9% 90%; /* Border color for inputs such as Input /, Select /, Textarea / */ --input: 240deg 5.88% 90%; --input-placeholder: 217 10.6% 65%; --input-background: 0 0% 100%; /* Used for focus ring */ --ring: 222.2 84% 4.9%; /* Border radius for card, input and buttons */ --radius: 0.5rem; /* custom */ /* 遮罩颜色 */ --overlay: 0deg 0% 0% / 30%; /* 基本文字大小 */ --font-size-base: 16px; /* component UI */ /* menu */ --sidebar: 0 0% 100%; --sidebar-deep: 216 20.11% 95.47%; --menu: var(--sidebar); /* header */ --header: 0 0% 100%; accent-color: var(--primary); color-scheme: light; }默认主题黑暗模式变量.dark, .dark[data-themecustom], .dark[data-themedefault] { /* Default background color of body /...etc */ --background: 222.34deg 10.43% 12.27%; /* 主体区域背景色 */ --background-deep: 220deg 13.06% 9%; --foreground: 0 0% 95%; /* Background color for Card / */ --card: 222.34deg 10.43% 12.27%; /* --card: 222.2 84% 4.9%; */ --card-foreground: 210 40% 98%; /* Background color for popovers such as DropdownMenu /, HoverCard /, Popover / */ --popover: 222.82deg 8.43% 12.27%; --popover-foreground: 210 40% 98%; /* Muted backgrounds such as TabsList /, Skeleton / and Switch / */ --muted: 220deg 6.82% 17.25%; --muted-foreground: 215 20.2% 65.1%; /* 主题颜色 */ /* --primary: 245 82% 67%; */ --primary-foreground: 0 0% 98%; /* Used for destructive actions such as Button variantdestructive */ --destructive: 0 78% 68%; --destructive-foreground: 0 0% 98%; /* Used for success actions such as message */ --success: 144 57% 58%; --success-foreground: 0 0% 98%; /* Used for warning actions such as message */ --warning: 42 84% 61%; --warning-foreground: 0 0% 98%; /* 颜色次要 */ --secondary: 240 5% 17%; --secondary-foreground: 0 0% 98%; /* Used for accents such as hover effects on DropdownMenuItem, SelectItem...etc */ --accent: 0deg 0% 100% / 8%; --accent-hover: 0deg 0% 100% / 12%; --accent-foreground: 0 0% 98%; /* Darker color */ --heavy: 0deg 0% 100% / 12%; --heavy-foreground: var(--accent-foreground); /* Default border color */ --border: 240 3.7% 15.9%; /* Border color for inputs such as Input /, Select /, Textarea / */ --input: 0deg 0% 100% / 10%; --input-placeholder: 218deg 11% 65%; --input-background: 0deg 0% 100% / 5%; /* Used for focus ring */ --ring: 222.2 84% 4.9%; /* 基本圆角大小 */ --radius: 0.5rem; /* Custom */ /* 遮罩颜色 */ --overlay: 0deg 0% 0% / 40%; /* 基本文字大小 */ --font-size-base: 16px; /* component UI */ --sidebar: 222.34deg 10.43% 12.27%; --sidebar-deep: 220deg 13.06% 9%; --menu: var(--sidebar); --header: 222.34deg 10.43% 12.27%; color-scheme: dark; }从上面两段可以看出几个关键设计点黑暗模式的选择器统一为.dark类可叠加[data-themecustom]/[data-themedefault]通过color-scheme告知浏览器原生控件滚动条、表单控件采用对应的明暗配色并用accent-color: var(--primary)让复选框、单选钮等原生控件跟随主题色。覆盖默认的 CSS 变量你只需要在自己的 CSS 文件中覆盖想要修改的变量即可无需改动框架源码。例如要把 Card 的默认背景色改为深灰色默认主题下:root { /* Background color for Card / */ --card: 0 0% 30%; }黑暗模式下.dark, .dark[data-themecustom], .dark[data-themedefault] { /* Background color for Card / */ --card: 222.34deg 10.43% 12.27%; }覆盖时注意三点一是变量必须使用hsl格式不带hsl()与逗号二是「默认主题下」写在:root而「黑暗模式下」需要同时命中.dark相关选择器以保证优先级三是--card这类带-foreground成对的变量通常需要成对覆盖才能获得一致的对比度。更改品牌主色品牌主色Primary是影响观感最直接的变量。框架要求以hsl格式配置你可以在应用目录下的preferences.ts中通过defineOverridesPreferences自定义主色import { defineOverridesPreferences } from vben/preferences; export const overridesPreferences defineOverridesPreferences({ // overrides theme: { // 错误色 colorDestructive: hsl(348 100% 61%), // 主题色 colorPrimary: hsl(212 100% 45%), // 成功色 colorSuccess: hsl(144 57% 58%), // 警告色 colorWarning: hsl(42 84% 61%), }, });提示颜色必须使用hsl格式可借助第三方在线工具进行颜色格式转换修改后需要清空浏览器缓存方可生效——这一点在源码中也有明确注释见各应用 preferences.ts 文件头部的「更改配置后请清空缓存否则可能不生效」。需要说明的是文档中给出的colorPrimary等默认值hsl(212 100% 45%)等与 默认偏好配置 中theme一节的取值完全一致说明这份示例就是框架的出厂默认值你只需替换其中的色值即可完成品牌换肤。源码视角品牌色如何生效品牌色的四个配置项之所以能以「一个色值驱动整站」是因为 update-css-variables.ts 中的updateMainColorVariables会调用generatorColorVariables把用户配置的单一色值展开成整套色阶变量再映射到语义变量上const colorMappings { --green-500: --success, --primary-500: --primary, --red-500: --destructive, --yellow-500: --warning, };也就是说你配置的colorPrimary会被生成一组--primary-50至--primary-950的完整色阶经由 theme-colors 的getColors展开并统一转为hsl格式其中500号色阶作为主色写入--primary。这也是为什么仅仅给出一个主色值就能让按钮、选中态、焦点环、链接等所有引用--primary的地方一起变色。内置主题框架内置了多种主题你可以在preferences.ts中通过builtinType进行配置import { defineOverridesPreferences } from vben/preferences; export const overridesPreferences defineOverridesPreferences({ // overrides theme: { builtinType: default, }, });内置主题类型列表框架内置了 16 种主题且支持自定义主题理论上可以无限扩展。完整的类型定义如下type BuiltinThemeType | custom | deep-blue | deep-green | default | gray | green | neutral | orange | pink | red | rose | sky-blue | slate | stone | violet | yellow | zinc | (Recordnever, never string);这段联合类型末尾的(Recordnever, never string)是一个巧妙的类型技巧它让BuiltinThemeType在保留既有字面量提示的同时也能接收任意字符串从而支持你自定义主题名如my-theme而不报类型错误。该类型定义可在 app.d.ts 中查看。内置主题浅色变量每个内置主题都是通过[data-themexxx]选择器覆盖一组变量实现的。浅色模式下所有主题共享:root中的基础变量如--background: 0 0% 100%再各自覆盖--primary相关色阶、--ring、--secondary、--muted等变量。以几个代表主题为例:root { --font-family: -apple-system, blinkmacsystemfont, Segoe UI, roboto, Helvetica Neue, arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; /* Default background color of body /...etc */ --background: 0 0% 100%; /* 主体区域背景色 */ --background-deep: 216 20.11% 95.47%; --foreground: 222 84% 5%; /* Background color for Card / */ --card: 0 0% 100%; --card-foreground: 222.2 84% 4.9%; /* Background color for popovers such as DropdownMenu /, HoverCard /, Popover / */ --popover: 0 0% 100%; --popover-foreground: 222.2 84% 4.9%; /* Muted backgrounds such as TabsList /, Skeleton / and Switch / */ --muted: 240 4.8% 95.9%; --muted-foreground: 240 3.8% 46.1%; /* 主题颜色 */ --primary: 212 100% 45%; --primary-foreground: 0 0% 98%; /* Used for destructive actions such as Button variantdestructive */ --destructive: 0 78% 68%; --destructive-foreground: 0 0% 98%; /* Used for success actions such as message */ --success: 144 57% 58%; --success-foreground: 0 0% 98%; /* Used for warning actions such as message */ --warning: 42 84% 61%; --warning-foreground: 0 0% 98%; /* Secondary colors for Button / */ --secondary: 240 5% 96%; --secondary-foreground: 240 6% 10%; /* Used for accents such as hover effects on DropdownMenuItem, SelectItem...etc */ --accent: 240 5% 96%; --accent-hover: 200deg 10% 90%; --accent-foreground: 240 6% 10%; /* Darker color */ --heavy: 192deg 9.43% 89.61%; --heavy-foreground: var(--accent-foreground); /* Default border color */ --border: 240 5.9% 90%; /* Border color for inputs such as Input /, Select /, Textarea / */ --input: 240deg 5.88% 90%; --input-placeholder: 217 10.6% 65%; --input-background: 0 0% 100%; /* Used for focus ring */ --ring: 222.2 84% 4.9%; /* Border radius for card, input and buttons */ --radius: 0.5rem; /* custom */ /* 遮罩颜色 */ --overlay: 0deg 0% 0% / 30%; /* 基本文字大小 */ --font-size-base: 16px; /* component UI */ /* menu */ --sidebar: 0 0% 100%; --sidebar-deep: 0 0% 100%; --menu: var(--sidebar); /* header */ --header: 0 0% 100%; accent-color: var(--primary); color-scheme: light; } [data-themeviolet] { /* --background: 0 0% 100%; */ --foreground: 224 71.4% 4.1%; --card: 0 0% 100%; --card-foreground: 224 71.4% 4.1%; --popover: 0 0% 100%; --popover-foreground: 224 71.4% 4.1%; --primary-foreground: 210 20% 98%; --secondary: 220 14.3% 95.9%; --secondary-foreground: 220.9 39.3% 11%; --muted: 220 14.3% 95.9%; --muted-foreground: 220 8.9% 46.1%; --accent: 220 14.3% 95.9%; --accent-foreground: 220.9 39.3% 11%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 210 20% 98%; --border: 220 13% 91%; --input: 220 13% 91%; --ring: 262.1 83.3% 57.8%; } [data-themepink] { /* --background: 0 0% 100%; */ --foreground: 240 10% 3.9%; --card: 0 0% 100%; --card-foreground: 240 10% 3.9%; --popover: 0 0% 100%; --popover-foreground: 240 10% 3.9%; --primary-foreground: 355.7 100% 97.3%; --secondary: 240 4.8% 95.9%; --secondary-foreground: 240 5.9% 10%; --muted: 240 4.8% 95.9%; --muted-foreground: 240 3.8% 46.1%; --accent: 240 4.8% 95.9%; --accent-foreground: 240 5.9% 10%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; --border: 240 5.9% 90%; --input: 240 5.9% 90%; --ring: 346.8 77.2% 49.8%; } [data-themesky-blue] { /* --background: 0 0% 100%; */ --foreground: 222.2 84% 4.9%; --card: 0 0% 100%; --card-foreground: 222.2 84% 4.9%; --popover: 0 0% 100%; --popover-foreground: 222.2 84% 4.9%; --primary-foreground: 210 40% 98%; --secondary: 210 40% 96.1%; --secondary-foreground: 222.2 47.4% 11.2%; --muted: 210 40% 96.1%; --muted-foreground: 215.4 16.3% 46.9%; --accent: 210 40% 96.1%; --accent-foreground: 222.2 47.4% 11.2%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 210 40% 98%; --border: 214.3 31.8% 91.4%; --input: 214.3 31.8% 91.4%; --ring: 221.2 83.2% 53.3%; } [data-themegreen] { /* --background: 0 0% 100%; */ --foreground: 240 10% 3.9%; --card: 0 0% 100%; --card-foreground: 240 10% 3.9%; --popover: 0 0% 100%; --popover-foreground: 240 10% 3.9%; --primary-foreground: 355.7 100% 97.3%; --secondary: 240 4.8% 95.9%; --secondary-foreground: 240 5.9% 10%; --muted: 240 4.8% 95.9%; --muted-foreground: 240 3.8% 46.1%; --accent: 240 4.8% 95.9%; --accent-foreground: 240 5.9% 10%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; --border: 240 5.9% 90%; --input: 240 5.9% 90%; --ring: 142.1 76.2% 36.3%; } [data-themezinc] { /* --background: 0 0% 100%; */ --foreground: 240 10% 3.9%; --card: 0 0% 100%; --card-foreground: 240 10% 3.9%; --popover: 0 0% 100%; --popover-foreground: 240 10% 3.9%; --primary-foreground: 0 0% 98%; --secondary: 240 4.8% 95.9%; --secondary-foreground: 240 5.9% 10%; --muted: 240 4.8% 95.9%; --muted-foreground: 240 3.8% 46.1%; --accent: 240 4.8% 95.9%; --accent-foreground: 240 5.9% 10%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; --border: 240 5.9% 90%; --input: 240 5.9% 90%; --ring: 240 5.9% 10%; }其余内置主题rose、deep-blue、deep-green、orange、yellow、neutral、slate、gray等遵循完全相同的模式均以[data-themexxx]覆盖--foreground、--secondary、--muted、--accent、--destructive、--border、--input、--ring等成组变量各主题间的差异主要体现在--ring焦点环色实际由主题色派生与中性色系zinc/neutral/slate/gray分别对应不同色相的中性灰上。内置主题黑暗模式变量黑暗模式下选择器变为.dark[data-themexxx]或[data-themexxx] .dark的复合写法且每个主题都会额外覆盖--sidebar、--sidebar-deep、--header等布局区域变量。以violet与zinc为例.dark, .dark[data-themecustom], .dark[data-themedefault] { /* Default background color of body /...etc */ --background: 222.34deg 10.43% 12.27%; /* 主体区域背景色 */ --background-deep: 220deg 13.06% 9%; --foreground: 0 0% 95%; /* Background color for Card / */ --card: 222.34deg 10.43% 12.27%; --card-foreground: 210 40% 98%; /* Background color for popovers such as DropdownMenu /, HoverCard /, Popover / */ --popover: 222.82deg 8.43% 12.27%; --popover-foreground: 210 40% 98%; /* Muted backgrounds such as TabsList /, Skeleton / and Switch / */ --muted: 240 3.7% 15.9%; --muted-foreground: 240 5% 64.9%; /* 主题颜色 */ --primary-foreground: 0 0% 98%; /* Used for destructive actions such as Button variantdestructive */ --destructive: 0 78% 68%; --destructive-foreground: 0 0% 98%; /* Used for success actions such as message */ --success: 144 57% 58%; --success-foreground: 0 0% 98%; /* Used for warning actions such as message */ --warning: 42 84% 61%; --warning-foreground: 0 0% 98%; /* 颜色次要 */ --secondary: 240 5% 17%; --secondary-foreground: 0 0% 98%; /* Used for accents such as hover effects on DropdownMenuItem, SelectItem...etc */ --accent: 216 5% 19%; --accent-hover: 216 5% 24%; --accent-foreground: 0 0% 98%; /* Darker color */ --heavy: 216 5% 24%; --heavy-foreground: var(--accent-foreground); /* Default border color */ --border: 240 3.7% 22%; /* Border color for inputs such as Input /, Select /, Textarea / */ --input: 0deg 0% 100% / 10%; --input-placeholder: 218deg 11% 65%; --input-background: 0deg 0% 100% / 5%; /* Used for focus ring */ --ring: 222.2 84% 4.9%; /* 基本圆角大小 */ --radius: 0.5rem; /* Custom */ /* 遮罩颜色 */ --overlay: 0deg 0% 0% / 40%; /* 基本文字大小 */ --font-size-base: 16px; /* component UI */ --sidebar: 222.34deg 10.43% 12.27%; --sidebar-deep: 220deg 13.06% 9%; --menu: var(--sidebar); /* header */ --header: 222.34deg 10.43% 12.27%; color-scheme: dark; } .dark[data-themeviolet], [data-themeviolet] .dark { --background: 224 71.4% 4.1%; --background-deep: var(--background); --foreground: 210 20% 98%; --card: 224 71.4% 4.1%; --card-foreground: 210 20% 98%; --popover: 224 71.4% 4.1%; --popover-foreground: 210 20% 98%; --primary-foreground: 210 20% 98%; --secondary: 215 27.9% 16.9%; --secondary-foreground: 210 20% 98%; --muted: 215 27.9% 16.9%; --muted-foreground: 217.9 10.6% 64.9%; --accent: 215 27.9% 16.9%; --accent-foreground: 210 20% 98%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 210 20% 98%; --border: 215 27.9% 16.9%; --input: 215 27.9% 16.9%; --ring: 263.4 70% 50.4%; --sidebar: 224 71.4% 4.1%; --sidebar-deep: 224 71.4% 4.1%; --header: 224 71.4% 4.1%; } .dark[data-themezinc], [data-themezinc] .dark { --background: 240 10% 3.9%; --background-deep: var(--background); --foreground: 0 0% 98%; --card: 240 10% 3.9%; --card-foreground: 0 0% 98%; --popover: 240 10% 3.9%; --popover-foreground: 0 0% 98%; --primary-foreground: 240 5.9% 10%; --secondary: 240 3.7% 15.9%; --secondary-foreground: 0 0% 98%; --muted: 240 3.7% 15.9%; --muted-foreground: 240 5% 64.9%; --accent: 240 3.7% 15.9%; --accent-foreground: 0 0% 98%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; --border: 240 3.7% 15.9%; --input: 240 3.7% 15.9%; --ring: 240 4.9% 83.9%; --sidebar: 240 10% 3.9%; --sidebar-deep: 240 10% 3.9%; --header: 240 4.9% 83.9%; }注意.dark[data-themexxx]与[data-themexxx] .dark同时出现的原因框架同时支持「把dark类挂在html上」与「把dark类挂在某个子容器上」两种黑暗模式作用域方式两种写法保证了主题变量在两种场景下都能正确命中。内置主题的预设主色源码证据除了 CSS 变量内置主题还各自带有一个「预设主色」保存在 constants.ts 的BUILT_IN_THEME_PRESETS中。例如default预设主色为hsl(212 100% 45%)violet为hsl(245 82% 67%)pink为hsl(347 77% 60%)sky-blue为hsl(231 98% 65%)green为hsl(161 90% 43%)等。特别地zinc、neutral、slate、gray这类中性色主题在浅色/深色模式下使用了不同的主色如zinc浅色主色为hsl(240 5.9% 10%)深色主色为hsl(0 0% 98%)以保证明暗两种模式下文字与主题色的对比度。当选择某个内置主题时update-css-variables.ts 会按当前明暗模式取对应的预设主色并写回--primary变量——这就是「切换内置主题后整站主色随之变化」的实现机制。新增自定义主题想要扩展一个全新的主题只需两步在应用的src/preferences.ts内新增一个主题配置把builtinType设为你的主题名import { defineOverridesPreferences } from vben/preferences; export const overridesPreferences defineOverridesPreferences({ // overrides theme: { builtinType: my-theme, }, });在你的 CSS 文件中为新增主题补充 CSS 变量浅色与深色各一套/* light */ [data-thememy-theme] { --foreground: 224 71.4% 4.1%; --card: 0 0% 100%; --card-foreground: 224 71.4% 4.1%; --popover: 0 0% 100%; --popover-foreground: 224 71.4% 4.1%; --primary-foreground: 210 20% 98%; --secondary: 220 14.3% 95.9%; --secondary-foreground: 220.9 39.3% 11%; --muted: 220 14.3% 95.9%; --muted-foreground: 220 8.9% 46.1%; --accent: 220 14.3% 95.9%; --accent-foreground: 220.9 39.3% 11%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 210 20% 98%; --border: 220 13% 91%; --input: 220 13% 91%; --ring: 262.1 83.3% 57.8%; } /* dark */ .dark[data-thememy-theme], [data-thememy-theme] .dark { --background: 224 71.4% 4.1%; --background-deep: var(--background); --foreground: 210 20% 98%; --card: 224 71.4% 4.1%; --card-foreground: 210 20% 98%; --popover: 224 71.4% 4.1%; --popover-foreground: 210 20% 98%; --primary-foreground: 210 20% 98%; --secondary: 215 27.9% 16.9%; --secondary-foreground: 210 20% 98%; --muted: 215 27.9% 16.9%; --muted-foreground: 217.9 10.6% 64.9%; --accent: 215 27.9% 16.9%; --accent-foreground: 210 20% 98%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 210 20% 98%; --border: 215 27.9% 16.9%; --input: 215 27.9% 16.9%; --ring: 263.4 70% 50.4%; --sidebar: 224 71.4% 4.1%; --sidebar-deep: 224 71.4% 4.1%; }新增主题名之所以能够直接通过builtinType传入正是得益于BuiltinThemeType末尾的(Recordnever, never string)开放类型而 update-css-variables.ts 会把builtinType写入html的data-theme属性从而触发你自定义的[data-thememy-theme]选择器生效。黑暗模式黑暗模式同样通过 CSS 变量驱动在preferences.ts中配置theme.mode即可import { defineOverridesPreferences } from vben/preferences; export const overridesPreferences defineOverridesPreferences({ // overrides theme: { mode: dark, }, });mode的取值类型为ThemeModeType auto | dark | light见 app.d.ts即支持「自动跟随系统 / 强制深色 / 强制浅色」三种模式。源码层面update-css-variables.ts 中的isDarkTheme会在auto模式下通过window.matchMedia((prefers-color-scheme: dark))检测系统偏好然后将dark类添加或移除到html根元素上配合上文.dark选择器下的整套深色变量完成全局明暗切换。自定义侧边栏颜色侧边栏颜色通过--sidebar变量配置菜单色--menu默认引用var(--sidebar)默认主题下:root { --sidebar: 0 0% 100%; }黑暗模式下.dark, .dark[data-themecustom], .dark[data-themedefault] { --sidebar: 222.34deg 10.43% 12.27%; }自定义顶栏颜色顶栏header颜色通过--header变量配置默认主题下:root { --header: 0 0% 100%; }黑暗模式下.dark, .dark[data-themecustom], .dark[data-themedefault] { --header: 222.34deg 10.43% 12.27%; }从默认变量表可以看到浅色主题下--sidebar、--header、--background均为0 0% 100%纯白而--sidebar-deep侧边栏更深一层的背景为216 20.11% 95.47%与--background-deep一致——这套「基础白 深一阶灰」的层级关系保证了页面不同区域的视觉分区。色弱模式色弱模式一般用于特殊场景如视觉障碍友好的产品场景。在preferences.ts中配置import { defineOverridesPreferences } from vben/preferences; export const overridesPreferences defineOverridesPreferences({ // overrides app: { colorWeakMode: true, }, });灰色模式灰色模式一般用于特殊场景如哀悼日、系统维护期将整站置灰。同样在preferences.ts的app一节中配置import { defineOverridesPreferences } from vben/preferences; export const overridesPreferences defineOverridesPreferences({ // overrides app: { colorGrayMode: true, }, });colorWeakMode与colorGrayMode的默认值均为false其类型定义与默认值可分别在 types.ts 与 config.ts 中确认。二者均属于app分组与主题分组theme是平级关系配置时注意层级不要写错。主题配置的运行时更新机制了解以上所有配置项的运行时行为有助于排查「改了配置不生效」的问题。核心逻辑集中在 update-css-variables.ts明暗模式检测到theme.mode变化后通过root.classList.toggle(dark, dark)控制html上的dark类内置主题检测到theme.builtinType变化后通过root.dataset.theme builtinType同步data-theme属性主题色根据内置主题预设主色或用户自定义的colorPrimary/colorDestructive/colorSuccess/colorWarning调用updateMainColorVariables把整套色阶转换为 HSL 变量并写入根元素圆角--radius按${radius}rem写入配合radius: 0.5这样的偏好值字体大小--font-size-base按${fontSize}px写入同时按calc(${fontSize}px * 0.875)联动更新--menu-font-size保证菜单字号与全局字号等比缩放。该更新逻辑在偏好设置被初始化或通过偏好设置面板修改时触发因此你在偏好设置面板中切换主题、明暗模式本质上也走的是同一套 CSS 变量更新路径——这解释了为何所有主题能力都「收敛」到 CSS 变量这一单一事实来源Single Source of Truth也让开发者可以放心地在任意组件中通过hsl(var(--xxx))引用主题能力。【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表