定制主题
Vue Amazing UI 的主题在颜色维度有四层配置面:7 个颜色种子(改整套)→ 组件级主色 theme.components(改某个组件的整套主色)→ 全局语义变量 --va-*(改某个作用域)→ 组件令牌(改单个视觉面);此外还有模式维度(theme.mode)与组件实例自身的 prop / style(见 ConfigProvider 的配置面)。默认颜色全部由派生函数按种子计算,组件样式只消费语义变量 --va-*,因此改一个种子,常态 / 悬停 / 按下 / 浅底 / 描边会同步变化。
派生规则:每个种子色先摊成 10 级色阶(第 1 档最浅、第 10 档最深),再按固定档位映射语义角色 —— 浅底取第 1 档、描边第 3 档、链接悬停第 4 档、悬停第 5 档、常态与主色文字第 6 档、按下第 7 档。暗色的色阶方向相反,悬停 / 按下改取第 7 / 5 档(链接悬停两模式共用悬停档),常态与主色文字仍取第 6 档。
默认主题色为
本页说明概念、派生规则与变量清单;可交互演示与 API 见 ConfigProvider。
术语说明:种子 / 派生 / 变量 / 令牌
| 术语 | 定义 | 对应代码 |
|---|---|---|
种子(seed) | 一整套色阶的起点色,共 7 个 | theme.seed.primary = '#1677ff' |
| 派生 | 由起点色计算出一整组深浅(常态 / 悬停 / 按下 / 浅底 / 描边) | derive(seed, mode),库内部完成 |
变量(--va-*) | 派生结果落地为 CSS 变量,组件只读取变量 | --va-primary-color 等 42 个 |
令牌(--va-<组件>-*) | 组件内部细节的公开变量名,用于单点覆盖 | --va-slider-handle-shadow-color |
核心结论:给定 7 个种子,42 个变量由库派生,组件只消费变量;因此换肤不重建组件,也不产生运行时开销。
主题模型:种子 → 派生 → 变量
本节先给出派生模型,下文所有用法都基于它:种子 → 派生 → 42 个 CSS 变量 → 组件只读变量。
seed + mode ──┐
├─→ derive(seed, mode) ─→ 42 个 --va-* ─┐
components ───┘ │ ├─→ 写到作用域节点 ─→ CSS 继承 ─→ var(--va-*)
└─→ 组件令牌 --va-<comp>-* ─┘ · 包裹元素 / <html> / 浮层根节点关键点:JS 只算一次、写一次,染色全在 CSS 引擎里完成。换主色时实际只变 15 个变量(主色 6 + info 3 + 链接 3 + 焦点环 1 + 品牌色暗底 2),其余 27 个连值都不变;暗色不是第二套种子,而是 derive 的另一个入参。
作用域与载体
| 载体 | 影响范围 | 适用场景 |
|---|---|---|
ConfigProvider 包裹元素(abstract: false,默认) | 自身子树 | 局部换肤;SSR 首帧即可序列化 |
<html>(abstract: true) | 整页,含页面链接与全部浮层 | 应用级主题,最外层传一次 |
| 浮层根节点(库自动转发) | 该弹层 | 无需配置,作用域内的弹窗 / 下拉自动跟随 |
任意祖先选择器上的 --va-* | 该子树 | 只改某个变量或某个组件令牌 |
优先级链
组件实例 prop / style(行内)
> 最近一层祖先上的组件令牌
> theme.components(写在作用域节点)
> seed 派生的全局变量
> 静态默认表同一个变量冲突时按普通 CSS 级联处理;--va-button-primary-color 与 --va-primary-color 之间不是优先级,而是 var(a, b) 的回退顺序。
排查清单:颜色没生效
| 现象 | 先查 |
|---|---|
| 只有这一个组件不对 | 是否被实例 style / color prop 等更高优先级覆盖 |
| 悬停或按下跳回默认色 | 只覆盖了常态,需整组覆盖(常态 / 悬停 / 按下) |
| 弹窗 / 下拉没跟随 | 作用域模式下是否在 Provider 子树内;应用级主题是否用了 abstract: true |
| 暗色只变了一半 | 纯 CSS 切暗色时 data-va-mode 必须写在实际作用域节点上 |
| 覆盖了组件令牌但无效 | 该视觉面是否已公开(见组件级令牌),是否写在 <style> 声明而非消费处 |
自定义 SVG 不变色 | fill 是 presentation attribute,不解析 var(),请写进 style |
构建期静态表、三张变量表、内部桥与公开令牌的双写约定、
Teleport转发协议、verify:theme守护等实现细节,属于贡献者文档,见仓库development/theme-system.md;面向使用者的结论已全部收在本页。
颜色种子:seed
| 种子 | 默认值 | 说明 |
|---|---|---|
primary | #1677ff | 品牌主色 |
success | #52c41a | 成功色 |
warning | #faad14 | 警告色 |
error | #ff4d4f | 错误 / 危险色 |
info | 跟随 primary | 信息色;未传时复用主色的三件套 |
neutralText | #000000 | 中性文本基准(透明度阶梯的叠加色) |
neutralBg | #ffffff | 中性背景基准(显式传入时两个模式共用) |
种子只接受不透明的 #rgb / #rrggbb(#rrggbbff 会收敛为 6 位);半透明(如 #1677ff80)会被判为非法并在开发环境告警、回退该字段默认值,不会中断其余字段的派生 —— 否则色阶基色会变成半透明,按钮底色与文字对比度全部失真。
组件级主色:theme.components
只覆盖某个组件的主题色,其余组件仍用全局种子;组件配置优先于 seed
旧版 theme.Button.primaryColor 的能力由 theme.components 承接:这里只放通用主色,组件内部的细分令牌(如 Slider 的 rail / tooltip、Button 的 ripple)仍是 CSS 变量、不在 components 配置面里,需要时用组件级令牌覆盖。
<script setup lang="ts">
import type { ConfigProviderTheme } from 'vue-amazing-ui'
const theme: ConfigProviderTheme = {
seed: { primary: '#1677ff' },
components: {
Button: { primaryColor: '#18a058' },
Slider: { primaryColor: '#18a058' }
}
}
</script>
<template>
<ConfigProvider :theme="theme">
<Button type="primary">Button 使用组件主色</Button>
<Slider :value="40" />
</ConfigProvider>
</template>- 组件配置优先于
seed:Button用#18a058派生,其余组件仍用#1677ff; - 组件主色与
seed共用同一校验口径:接受#rgb/#rrggbb/#rrggbbff(alpha必须为ff),非法值告警并忽略该组件配置; - 当前有
40个组件接入了组件级主色(完整清单见组件级令牌),覆盖对外暴露的主色使用点;组合组件内的子组件与派生组件(如DropdownButton的分割线)跟随宿主组件的令牌,不单独配置。未接入的组件(如Dropdown)写入键名会在开发环境告警、不会静默生效,需要时用组件令牌或嵌套作用域; - 运行期移除某个组件的配置(整体替换
theme,或删掉components.Button)会回落到seed; - 组件配置写在
ConfigProvider的作用域节点上(abstract: false写包裹元素,abstract: true写<html>),优先级高于seed与外层祖先的--va-primary-*。Button/Slider/Menu仍可在更近的元素上覆盖公开组件令牌;其余组件要再覆盖时,请用更内层的ConfigProvider重新配置该组件; - 组件配置沿
DOM继承:外层设置的components.Button会继续作用于内层;内层只改seed不会把它重置,需要重置时在内层显式设置该组件的primaryColor; - 组件主色按
Provider解析出的mode派生;如果页面是用纯CSSdata-va-mode切暗色、而Provider没有mode,请补传mode,否则组件主色会按浅色色阶派生; - 组件级主色只影响该组件自身的主色使用点;组合组件内的子组件(如
InputSearch内的Input、Popconfirm内的Button)按子组件自己的theme.components配置,需要时分别配置; abstract: true时组件配置要和seed/mode放在同一个Provider上;只有组件配置时请用abstract: false,否则它不参与<html>写入,开发环境会告警;- 配置
Button/Slider/Menu时,Provider会同时写出内部桥与公开令牌(同一份派生结果的两套名字),组件样式只读其中一套;两种入口最终落到同一个变量,实现细节见仓库development/theme-system.md的「组件级主色怎么落地」; - 在线演示:组件级主色。
运行期切换:响应式 theme
修改种子即可,推荐用 computed 派生;整体替换 theme 对象或就地改写 seed 字段都会生效
<!-- App.vue -->
<script setup lang="ts">
import { computed, ref } from 'vue'
import type { ConfigProviderTheme } from 'vue-amazing-ui'
const primary = ref<string>('#ff6900')
const theme = computed<ConfigProviderTheme>(() => ({
seed: { primary: primary.value }
}))
</script>
<template>
<!-- 应用级主题:显式 abstract=true,变量写到 <html>,浮层与页面链接一并跟随 -->
<ConfigProvider :abstract="true" :theme="theme">
<RouterView />
</ConfigProvider>
</template>- 在线演示:运行期切换主题。
明暗模式:light / dark / auto
mode 是派生函数的入参,不是第二套种子;dark 与 light 共用同一组种子
<script setup lang="ts">
import { ref } from 'vue'
import type { ConfigProviderTheme, ThemeMode } from 'vue-amazing-ui'
const mode = ref<ThemeMode>('light')
const theme = ref<ConfigProviderTheme>({ mode: mode.value })
</script>
<template>
<ConfigProvider :abstract="true" :theme="theme">
<RouterView />
</ConfigProvider>
</template>mode="light" | "dark":显式指定;mode="auto":跟随系统prefers-color-scheme,变化时自动重写变量,卸载后解除监听;- 未传
mode:沿用外层作用域(最外层为浅色); - 在线演示:明暗模式切换。
最外层只切 mode 而未传 seed(也没有可继承的种子)时,Provider 不会写任何变量,而是把 data-va-mode 写到作用域节点上,由静态默认表接管 —— 因此切换暗色是纯 CSS 行为,零样式重建。
暗色表同时输出 color-scheme: dark(浅色表对应的 [data-va-mode='light'] 输出 color-scheme: light),原生滚动条、表单控件与默认背景会随模式切换。
mode="auto" 在 SSR 下的首帧
服务端拿不到 prefers-color-scheme,此时下发任何模式都会和客户端首次渲染不一致(hydration mismatch)。因此 abstract: false + mode="auto" 时,首帧不下发变量与 data-va-mode,由客户端挂载后补写;服务端首帧会用静态默认表(浅色)。需要首帧即暗色时,请在 SSR 侧显式传 mode="dark"。
默认的 abstract: false 会把变量序列化进包裹元素,SSR 首帧即正确;abstract: true 不产出可序列化的变量(变量在客户端挂载后写 <html>),首帧沿用静态默认表。
作用域换肤:嵌套 ConfigProvider
主题沿 DOM 级联:在某个区域外层再包一个 ConfigProvider,换肤只作用于该子树
<template>
<ConfigProvider :theme="{ seed: { primary: '#1677ff' } }">
<Button type="primary">外层主色</Button>
<ConfigProvider :abstract="false" :theme="{ seed: { primary: '#18a058' } }">
<Button type="primary">子树主色</Button>
</ConfigProvider>
</ConfigProvider>
</template>- 默认
abstract: false:实例渲染包裹元素,变量与data-va-mode写在该元素上,只作用于自身子树,SSR首帧可直接序列化; Teleport到body的浮层(弹窗 / 下拉 / 消息等)由边界转发补齐:浮层根节点带上当前作用域的令牌与模式,因此作用域内的浮层也跟随,不会退回静态默认表;- 需要页面级生效(主题化
body级链接、body 背景等)时,在最外层传:abstract="true",由它把变量写到<html>; - 「
<html>写入者」按是否配置了全局主题域(种子或模式)判定:只配置theme.components的实例不参与写入权仲裁(abstract: true时会告警,应用级组件配置请与seed/mode同层);未传theme(或传空对象)的ConfigProvider不占用该名额,因此应用根部放一个空主题实例,不会让页面里的主题实例失效; - 嵌套实例未显式传
mode时继承外层模式(暗色区域内的子作用域不会派生出浅色变量); - 嵌套实例未显式传
seed时继承外层种子(「外层换品牌色 + 内层只切暗色」不会退回默认蓝);传了则整体替换,不做逐字段合并; - 组件级配置写在同一个作用域节点上:内层
Provider的theme.components覆盖外层;宿主要在组件配置之上再覆盖,请写在更靠近组件的元素上,或用组件实例prop; - 嵌套实例若显式传
abstract: true(无包裹元素),没有可承载变量的节点,只能随外层生效,开发环境会告警; - 作用域标记在组件
setup时确定:运行期给父级增删主题不会改变已挂载子级的判定(例如父级随后移除主题,子级不会接管<html>)。需要动态切换时请重新挂载子树,或改用abstract: false的分层作用域; - 在最外层只切
mode、且没有可继承的种子时,Provider不写任何变量,只写data-va-mode:静态表已按模式声明全量变量(含[data-va-mode='light']回环),宿主对:root单变量的覆盖不会被遮蔽; - 在线演示:作用域换肤。
单变量覆盖:--va-*
--va-* 是公开契约,宿主可直接在任意作用域覆盖
.my-panel {
--va-primary-color: #ff6900;
--va-primary-color-hover: #d95a00;
--va-primary-color-active: #b34b00;
}WARNING
只覆盖 --va-primary-color 而不覆盖 -hover / -active,会出现「常态变了、悬停没变」。换色应通过 ConfigProvider.seed 派生整套;只想改某个组件时用 theme.components.<Component>.primaryColor;或在同一作用域同时覆盖完整状态变量。
颜色变量清单:42 个 --va-*
共 42 个;新增变量必须同时满足「不是现有变量的函数」与「至少有一个组件消费」
| 分组 | 变量 |
|---|---|
| 主色 | --va-primary-color / -hover / -active;--va-primary-bg-color / --va-primary-border-color / --va-primary-text-color |
| 语义色 | --va-{success,warning,error,info}-color / -bg-color / -border-color |
| 文本 | --va-text-color-1 / -2 / -3 / --va-text-color-solid / --va-text-color-disabled |
| 背景 | --va-bg-container-color / --va-bg-elevated-color / --va-bg-layout-color / --va-bg-spotlight-color / --va-bg-brand-dark-color / --va-bg-brand-dark-deep-color |
| 边框 | --va-border-color / --va-border-split-color |
| 填充 | --va-fill-color-1 / --va-fill-color-2 / --va-fill-color-3 / --va-fill-color-4 |
| 阴影 | --va-shadow-color / --va-focus-shadow / --va-popup-shadow |
| 遮罩 | --va-mask-color |
| 链接 | --va-link-color / -hover / -active |
--va-primary-text-color/--va-link-*与主色同值,不做对比度改写;--va-primary-text-color的消费面是「主色文字」场景(Menu选中项、Tabs激活页签、Pagination当前页),单独覆盖它可以把「色块」与「文字」的取色拉开;--va-text-color-solid是实色底(彩色底 / 黑色遮罩)上的文字色,两种模式恒为白;按钮主色底、Badge计数、Avatar、图片预览的白色chrome都取它;--va-bg-elevated-color是浮层底(浅色#ffffff/ 暗色#1f1f1f):暗色下它比--va-bg-container-color提亮一档,Modal/Drawer/Message/Notification/Dialog/Popover/Popconfirm/Dropdown/Select面板 / 日期面板 /ColorPicker面板都取它,否则浮层与页面同色、层级无法分辨;--va-bg-spotlight-color是反色浮层底(浅色rgba(0,0,0,.85)/ 暗色#424242),Tooltip默认取它;--va-bg-brand-dark-color/--va-bg-brand-dark-deep-color是品牌色暗底(默认主色下#001129/#000a17):取主色的色相与饱和度、亮度压到8%/4.5%,两个模式取值相同。Menu的theme="dark"皮肤取它们做根列表 / 浮层面板与内联子菜单的底色,因此换主题色时深色皮肤跟着变色相;配置了theme.components.Menu.primaryColor时按该组件主色重新派生(优先于seed);是否启用这套皮肤仍只由theme属性决定,与data-va-mode无关;--va-mask-color两模式固定rgba(0, 0, 0, 0.45),Modal/Drawer/ 图片预览的遮罩都取它(遮罩不跟随正文色,否则暗色下会变成白色蒙层);--va-fill-color-3是最强的一档中性叠加(浅色rgba(0,0,0,.15)/ 暗色rgba(255,255,255,.18)),Watermark的默认水印色取它,因此暗色下自动变成半透明白;显式传textStyle.color时以传入值为准;--va-fill-color-4是最淡的一档中性叠加(浅色rgba(0,0,0,.02)/ 暗色rgba(255,255,255,.04)),用于默认标签底、Result内容区底纹、表格展开行;- 编号
1~4只表示档位,不代表强度顺序(3最强、4最淡); - 阴影变量是完整
box-shadow值,直接整体赋值即可; --va-shadow-color是方向性 / 局部阴影的基色(浅色极淡黑、暗色加深);不要拿--va-fill-color-2当阴影色,它在暗色下是白色,会形成光晕;- 例外是落在自身遮罩上的面板阴影(如
Drawer的四向面板):遮罩在暗色下已是rgba(0,0,0,.45)的深色叠加,再用加深的基色会在面板与遮罩交界处叠出一条黑边,这类阴影改用固定rgba(0,0,0,.08)基色。
关于可读性
系统不替品牌色兜底。如果主色偏浅(如黄色、亮青),主色文字与主色按钮上的白字对比度会不足 —— 这时应当换一个更深的品牌色(或单独覆盖 --va-primary-text-color / --va-text-color-solid),而不是期待主题系统自动修正。
脚本取色:derive
组件样式只读 CSS 变量;需要在 JS / canvas / SVG 里拿到同一份色值时,用主入口导出的 derive
import { derive } from 'vue-amazing-ui'
import type { ThemeVars } from 'vue-amazing-ui'
// 与 <ConfigProvider :theme="{ seed, mode }"> 写出的 42 个变量逐值一致
const vars: ThemeVars = derive({ primary: '#18a058' }, 'dark')
vars['--va-primary-color'] // => '#178b4e'derive(seed?, mode?):seed为ThemeSeed(未传的字段取默认值),mode为已解析的'light'/'dark'(缺省'light');- 返回
ThemeVars(42 个--va-*的只读快照,键名见上一节清单),ThemeSnapshot是它的只读别名;结果带缓存,同一组输入返回同一对象; - 需要
theme.mode = 'auto'的语义时,请先在业务侧把auto解析成light/dark再传入 ——derive只接受已解析的模式(ResolvedMode); - 其它主题出口:
DEFAULT_PRIMARY/DEFAULT_SEEDS(默认主色与默认种子)、THEME_VAR_NAMES(变量名清单)、MODE_ATTRIBUTE(data-va-mode属性名); - 旧版
getColorPalettes/getAlphaColor已移除:色阶与透明度色都改由derive的返回值和--va-*承担,避免出现两套取色口径。
组件级令牌与整组覆盖
只想改某一个组件时(例如「主色按钮变绿、链接仍是品牌蓝」),用 --va-<组件>-*;下面是完整清单与覆盖约定
- 与全局令牌一样是继承的
CSS变量,写在任意祖先选择器上即生效,不需要碰库内部类名; - 只覆盖常态会出现「悬停跳回默认色」,请整组覆盖(常态 / 悬停 / 按下);底色类令牌要同时看前景色(如滑动输入条的气泡);
- 令牌按「高频 + 可覆盖」逐步扩展,不追求组件全覆盖:只有当用户能在自己的选择器上覆盖、且确实有「只改这个组件」的场景时,才会公开;
- 在线演示:组件令牌覆盖。
本节由 tsx scripts/gen-component-vars-doc.ts 从 components/theme/component-vars.ts 生成,请勿手动修改;生成物需提交(不要加进 .gitignore)。
组件令牌是组件内部颜色变量的公开名字(--va-<组件>-*),也包括把组件主色接到具体皮肤上的桥接令牌。 它们与全局令牌一样是普通的 CSS 自定义属性,直接在选择器里赋值即可,沿 DOM 继承生效; 组件令牌只在消费处带默认值、自身不声明,因此写在任何祖先选择器上都能生效,也不会被组件样式反向压住。
组件级主色的支持范围
当前支持 40 个组件:Alert / AutoComplete / BackTop / Badge / Button / Calendar / Carousel / Cascader / Checkbox / ColorPicker / DatePicker / FloatButton / GradientText / Image / Input / InputNumber / InputSearch / LoadingBar / Menu / Message / Modal / Notification / Pagination / Popconfirm / Progress / Radio / Select / Slider / Spin / Steps / Swiper / Switch / Table / Tabs / Tag / TextScroll / Textarea / TimePicker / Timeline / Upload。 Button / Slider / Menu 通过注册表里的 themeRole 令牌映射;其余组件在样式里消费内部桥变量 --va-cp-<component>-primary-*,配置后会覆盖该组件的全部主色使用点。写错组件名会在编译期报错。
成组覆盖
同一个视觉元素的状态是成组的:只改常态会出现「悬停跳回默认色」,只改底色会出现 「文字不可读」。请整组覆盖,或改用 ConfigProvider.seed 让系统派生整套状态。
/* 主色按钮:常态 / 悬停 / 按下 */
.my-zone {
--va-button-primary-color: #18a058;
--va-button-primary-color-hover: #36ad6a;
--va-button-primary-color-active: #0c7a43;
}
/* 危险按钮:只覆盖常态即可,悬停 / 按下默认跟随常态色 */
.my-zone {
--va-button-danger-color: #d03050;
}
/* 滑动输入条:轨道(已选 / 未选)各两态 */
.my-zone {
--va-slider-track-color: #18a058;
--va-slider-track-color-hover: #36ad6a;
--va-slider-rail-color: #eef1f5;
--va-slider-rail-color-hover: #e3e8ef;
}
/* 数值气泡:底色与文字色必须成对 */
.my-zone {
--va-slider-tooltip-bg-color: #ffffff;
--va-slider-tooltip-color: #333639;
}变量清单
按钮 Button
color 属性会在这一个实例上内联写入 --va-button-primary-color 等令牌(实例级覆盖,优先级最高),因此传了 color 时下面这些令牌对该实例不生效。下拉按钮 DropdownButton 的共享分割线也跟随 --va-button-primary-color-hover / --va-button-danger-color-hover。
其中 --va-button-primary-color / --va-button-primary-color-hover / --va-button-primary-color-active / --va-button-solid-text-color 会跟随 ConfigProvider 的 theme.components.Button.primaryColor 自动派生;其余令牌需要用 CSS 直接覆盖。
主色
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-button-primary-color | 主按钮底色(常态) | var(--va-primary-color) |
--va-button-primary-color-hover | 主按钮底色(悬停) | var(--va-primary-color-hover) |
--va-button-primary-color-active | 主按钮底色(按下) | var(--va-primary-color-active) |
前景色
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-button-solid-text-color | 实色底上的文字色(primary / danger / reverse 共用) | var(--va-text-color-solid) |
危险色
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-button-danger-color | 危险按钮底色(常态) | var(--va-error-color) |
--va-button-danger-color-hover | 危险按钮底色(悬停);默认跟随常态色,只覆盖常态色时不会跳回全局红 | var(--va-button-danger-color, var(--va-error-color)) |
--va-button-danger-color-active | 危险按钮底色(按下);默认跟随常态色 | var(--va-button-danger-color, var(--va-error-color)) |
滑动输入条 Slider
其中 --va-slider-track-color / --va-slider-track-color-hover / --va-slider-handle-shadow-color / --va-slider-handle-shadow-color-hover-focus / --va-slider-dot-color-active 会跟随 ConfigProvider 的 theme.components.Slider.primaryColor 自动派生;其余令牌需要用 CSS 直接覆盖。
已选轨道
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-slider-track-color | 已选轨道底色(常态) | var(--va-primary-border-color) |
--va-slider-track-color-hover | 已选轨道底色(悬停) | var(--va-primary-color) |
未选轨道
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-slider-rail-color | 未选轨道底色(常态) | var(--va-fill-color-1) |
--va-slider-rail-color-hover | 未选轨道底色(悬停) | var(--va-fill-color-2) |
滑块
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-slider-handle-color | 滑块圆点底色 | var(--va-bg-elevated-color) |
--va-slider-handle-shadow-color | 滑块光环色(常态,常驻 2px) | var(--va-primary-border-color) |
--va-slider-handle-shadow-color-hover-focus | 滑块光环色(悬停 / 聚焦,放大到 4px) | var(--va-primary-color) |
刻度点
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-slider-dot-border-color | 刻度点描边色(常态) | var(--va-border-split-color) |
--va-slider-dot-border-color-hover | 刻度点描边色(悬停) | var(--va-fill-color-2) |
--va-slider-dot-color-active | 刻度点描边色(激活态,跟随组件级主色) | var(--va-primary-border-color) |
数值气泡
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-slider-tooltip-bg-color | 数值气泡底色 | var(--va-bg-spotlight-color) |
--va-slider-tooltip-color | 数值气泡文字色;改底色时需同步覆盖,否则浅底白字不可读 | var(--va-text-color-solid) |
导航菜单 Menu
下表的「浅色 / 深色」指 theme 属性(独立皮肤),与 data-va-mode 暗色模式无关:浅色皮肤的容器令牌跟随全局令牌派生(暗色模式下自动取暗色值),深色皮肤的三只表面令牌(根列表 / 浮层面板 / 内联子菜单)取品牌色暗底 --va-bg-brand-dark-color / --va-bg-brand-dark-deep-color(主色色相与饱和度、亮度压到 8% / 4.5%,两个模式同值),因此换主题色时深色皮肤同步换色相;是否启用这套皮肤只由 theme 属性决定。三只主色桥令牌由 theme.components.Menu.primaryColor 派生;--va-menu-item-selected-* 的默认值通过它们间接跟随组件主色,直接覆盖选中态令牌仍然优先。组件级 primaryColor 同样驱动深色皮肤的三只表面令牌(按该主色重新派生暗底,优先级高于 seed);直接覆盖令牌依然优先级最高。
其中 --va-menu-primary-color / --va-menu-primary-palette / --va-menu-primary-text-color 会跟随 ConfigProvider 的 theme.components.Menu.primaryColor 自动派生;其余令牌需要用 CSS 直接覆盖。
主色
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-menu-primary-color | 菜单主色桥:选中项文字 / 深色皮肤选中底 / 水平状态下划线 | var(--va-primary-color) |
--va-menu-primary-palette | 菜单主色浅底桥:浅色皮肤选中项底色(深色皮肤改用 --va-menu-primary-color) | var(--va-primary-bg-color) |
--va-menu-primary-text-color | 菜单主色文字桥:浅色皮肤选中项文字 / 水平菜单下划线 | var(--va-primary-text-color) |
容器
| 名称 | 说明 | 默认值(浅色皮肤 / 深色皮肤) |
|---|---|---|
--va-menu-background | 菜单根列表背景;弹出子菜单面板取 --va-menu-popup-background,不受它影响 | 浅色 var(--va-bg-container-color)深色 var(--va-bg-brand-dark-color, #001529) |
--va-menu-popup-background | 弹出子菜单(浮层面板)背景;深色皮肤取品牌色暗底,与根列表同色 | 浅色 var(--va-bg-elevated-color)深色 var(--va-bg-brand-dark-color, #001529) |
--va-menu-inline-submenu-background | 内联子菜单(inline 展开的下一级列表)背景;深色皮肤取更深一阶的品牌色暗底 | 浅色 var(--va-fill-color-1)深色 var(--va-bg-brand-dark-deep-color, #000c17) |
选中态
| 名称 | 说明 | 默认值(浅色皮肤 / 深色皮肤) |
|---|---|---|
--va-menu-item-selected-background | 选中项(含按下态)底色 | 浅色 var(--va-primary-bg-color)深色 var(--va-primary-color) |
--va-menu-item-selected-color | 选中项文字色 / 水平菜单下划线色 | 浅色 var(--va-primary-text-color)深色 #fff |
文字滚动 TextScroll
容器
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-text-scroll-bg-color | 滚动区域底色(横 / 纵两个变体共用) | var(--va-bg-container-color) |
--va-text-scroll-shadow-color | 滚动区域外围阴影色(横 / 纵两个变体共用) | var(--va-border-color) |
滚动条 Scrollbar
滚动条滑块
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-scrollbar-color | 滚动条滑块底色(常态) | var(--va-text-color-disabled) |
--va-scrollbar-color-hover | 滚动条滑块底色(悬停) | var(--va-text-color-3) |
表格 Table
容器
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-table-bg-color | 表格容器 / 数据行 / 固定列底色 | var(--va-bg-container-color) |
表头
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-table-header-bg-color | 表头单元格底色(含排序列表头与固定列表头) | var(--va-fill-color-4) |
底部
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-table-footer-bg-color | 表格底部(分页区)底色 | var(--va-fill-color-4) |
边框
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-table-border-color | 单元格分隔线 / 外边框 / 固定列滚动阴影;另作可排序表头底与可排序行悬停底(改浅会连带变亮这两处底色) | var(--va-border-split-color) |
卡片 Card
容器
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-card-bg-color | 卡片底色 | var(--va-bg-container-color) |
边框
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-card-border-color | 卡片外边框与标题分割线 | var(--va-border-split-color) |
警告提示 Alert
容器
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-alert-bg-color | 默认态提示框底色(语义态用 --va-{success,warning,error,info}-* 控制) | var(--va-fill-color-1) |
边框
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-alert-border-color | 默认态提示框边框(语义态用 --va-{success,warning,error,info}-border-color 控制) | var(--va-border-color) |
输入框 Input
容器
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-input-bg-color | 输入框底色(含自动填充背景) | var(--va-bg-container-color) |
边框
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-input-border-color | 输入框常态边框(聚焦 / 悬停仍由主色派生) | var(--va-border-color) |
前景色
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-input-text-color | 输入文字与光标颜色 | var(--va-text-color-1) |
--va-input-placeholder-color | 占位符文字颜色 | var(--va-text-color-disabled) |
文本域 Textarea
容器
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-textarea-bg-color | 文本域底色(含自动填充背景) | var(--va-bg-container-color) |
边框
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-textarea-border-color | 文本域常态边框(聚焦 / 悬停仍由主色派生) | var(--va-border-color) |
前景色
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-textarea-text-color | 输入文字与光标颜色 | var(--va-text-color-1) |
--va-textarea-placeholder-color | 占位符文字颜色 | var(--va-text-color-disabled) |
模态框 Modal
容器
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-modal-bg-color | 弹窗内容区底色 | var(--va-bg-elevated-color) |
前景色
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-modal-title-color | 弹窗标题颜色 | var(--va-text-color-1) |
--va-modal-text-color | 弹窗正文颜色 | var(--va-text-color-1) |
抽屉 Drawer
容器
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-drawer-bg-color | 抽屉面板底色 | var(--va-bg-elevated-color) |
边框
| 名称 | 说明 | 默认值 |
|---|---|---|
--va-drawer-header-border-color | 抽屉头部与内容区之间的分割线 | var(--va-border-split-color) |
--va-drawer-footer-border-color | 抽屉底部操作区上方的分割线 | var(--va-border-split-color) |
已知限制
Teleport 浮层只转发全局令牌:有生效
seed时42个--va-*会随浮层根节点下发 (只配置theme.components时只转发组件令牌,避免覆盖宿主用纯CSS写在:root上的主题), 但你在祖先上手写的 组件令牌不会被带过去。受影响场景:Menu的弹出型子菜单(mode="horizontal"、inlineCollapsed收起态)里的--va-menu-item-selected-*;Notification/Modal/Select等浮层内的Scrollbar的--va-scrollbar-*。
需要时请在
<html>或浮层的承载层上设置。Menu的inline模式、Scrollbar的非浮层用法不受影响。--va-menu-background只改根列表背景:弹出面板底色由--va-menu-popup-background控制、内联子菜单底色由--va-menu-inline-submenu-background控制,需分别覆盖。disabled态不受组件令牌影响:禁用态统一走中性令牌,这是刻意设计。Button的danger默认为单档:常态 / 悬停 / 按下三态默认同色(历史视觉档位缺失); 已支持只覆盖常态色(悬停 / 按下跟随),但默认状态本身没有档位差。--va-scrollbar-width是全局运行时变量(页面滚动锁定时由库写入<html>,供固定定位元素补偿宽度), 不属于组件令牌,也不跟随主题派生。
契约说明
- 本清单是按需扩展的,不代表组件全覆盖:只有上面列出的组件提供组件级令牌, 其余组件的配色请用全局令牌 /
props/ 作用域seed; - 组件的其它内部变量(尺寸、层级、按
props计算的实现细节、Tag色板、深色皮肤色板等)是私有实现, 不承诺、也不在本节列出; - 令牌名在 minor 版本内保持稳定,重命名按 major 处理。
暗色覆盖范围:固定色值
mode="dark" 覆盖所有消费 --va-* 的样式;下列颜色按设计固定,不随明暗切换
Tag的预设色板(pink/red/blue等13色)按模式声明为组件继承变量(--tag-*,组件自有资产,不属于--va-*契约):嵌套作用域与带data-va-mode的浮层都取最近作用域的值,不再是“暗色页面里永远走暗色板”;Badge/Result的自定义色板:浅色值固定,暗色另有一套按暗色阶梯重算的覆盖;语义状态(success/processing/error/warning)与Timeline的圆点直接取--va-*,随模式切换;- 深色
Sider:本身就是一套独立预设皮肤,改主题不应重定义它; theme="dark"的Menu:皮肤仍是一套独立预设(是否启用只由theme属性决定,不随data-va-mode切换),但三个表面色的默认值由主色派生(--va-bg-brand-dark-color/--va-bg-brand-dark-deep-color),换主色时同步换色相;需要让它跟随明暗模式或与页面容器同色时,把--va-menu-background/--va-menu-popup-background/--va-menu-inline-submenu-background分别指向--va-bg-container-color/--va-bg-elevated-color/--va-fill-color-1;Image预览与Video播放器的固定chrome(深色底 + 白色图标);- 各类中性投影(
box-shadow中的黑色阴影); Watermark的水印颜色默认取--va-fill-color-3(随模式变),只有显式传textStyle.color时才脱离主题。
自定义 SVG 不要写 fill="var(--va-*)"
SVG 的 presentation attribute(fill / stroke / stop-color)不解析 CSS 变量,写上去会被静默忽略并退回默认色。请写成 style="fill: var(--va-fill-color-2)" 或用 CSS 类绑定,pnpm verify:theme 会对该写法直接报错。
迁移:旧版主题 API
旧版 theme.common.primaryColor / theme.Button.primaryColor 已改为 seed / components;abstract 默认值与被移除的工具函数 / 私有变量见下方逐条
- <ConfigProvider :theme="{ common: { primaryColor: '#ff6900' } }">
+ <ConfigProvider :theme="{ seed: { primary: '#ff6900' } }">
- <ConfigProvider :theme="{ Button: { primaryColor: '#18a058' } }">
+ <ConfigProvider :theme="{ components: { Button: { primaryColor: '#18a058' } } }">- 组件级主色(
theme.Button.primaryColor)改为theme.components.Button.primaryColor,只覆盖通用主色;更细的部件颜色用组件级令牌或在子树外层包一个ConfigProvider换肤; abstract默认值由true改为false:不写abstract时实例会渲染一层包裹元素(tag可改为span等行内元素),主题只作用于自身子树;需要页面级主题(Teleport浮层、页面链接色)时在最外层显式传:abstract="true",嵌套层保持默认;- 旧版由
JS注入的--<组件名>-primary-color一类主题对象已移除:组件样式改为只消费--va-*,配置theme.components时由ConfigProvider在作用域节点写入内部桥变量(实现细节,不需要手工覆盖);曾用这些变量覆盖配色的样式需改为--va-<组件名>-*令牌; - 需要单独调某个组件的配色时,用 组件级令牌 的
--va-<组件>-*:它是CSS侧的公开名(不是旧版由JS注入的主题对象),组件私有变量仍不对外承诺; - 取色改用主题派生:
--va-*由ConfigProvider写入,JS/canvas/SVG场景用公开的derive(seed, mode)取同一份结果;旧版getColorPalettes/getAlphaColor已随本版移除; - 定时与暗色切换:
rafTimeout/cancelRaf改用setTimeout/ 原生requestAnimationFrame(返回类型AnimationFrameID一并移除),toggleDark改用theme.mode,或直接写<html data-va-mode="dark">; - 旧版通过行内变量覆盖组件配色的写法,改为覆盖上表的
--va-*(注意优先级随级联关系变化)。
离散 API:与 createDiscreteApi 的关系
离散实例的浮层挂在 body:传了 configProviderProps.theme 时由边界转发写到浮层根节点;未传时从 <html> 继承主应用主题
它不会改写 <html>,dispose() 也不会误清除主应用写入的变量。configProviderProps.theme(含 seed / mode / components)会作用于该实例自己的浮层(经内部转发通道写到浮层根节点,不污染全局);未传时浮层沿用 <html> 上的主应用主题。