主题定制
组件库的所有视觉表现都由 --m-* 形式的 CSS 自定义属性驱动。这套令牌定义在 miao-design/style.css 的 :root 中,严格对齐 MUI v5 的默认主题:调色板取自 MUI createPalette,阴影取自 shadows.js,缓动曲线与时长取自 createTransitions。
这意味着两件事:一是换肤只需要覆写变量;二是如果你的团队本来就在用 MUI 的设计语言,视觉可以直接对齐。
语义色
六组语义色,每组包含五个变量:
| 变量 | 含义 |
|---|---|
--m-<color> | 主色(main) |
--m-<color>-hover | 悬停态(dark) |
--m-<color>-light | 浅色变体(light) |
--m-<color>-contrast | 主色之上的文字色 |
--m-<color>-rgb | 以空格分隔的 RGB 通道,用于 rgb(var(--m-primary-rgb) / 0.2) 这类透明度写法 |
--m-primary#1976d2--m-secondary#9c27b0--m-success#2e7d32--m-warning#ed6c02--m-error#d32f2f--m-info#0288d1背景与浮层
--m-htmlapp 根背景--m-paper纸张底--m-card卡片底--m-popup浮层底--m-mask遮罩--m-popup 专门给下拉菜单、选择器、日期面板这类临时浮层使用(暗色下是 #242424 而非纯黑),--m-card 是兼容旧代码保留的卡片底。
交互态
--m-action-hoverhover 态底--m-action-selected选中态底--m-action-focus聚焦态--m-action-disabled禁用前景--m-action-disabled-bg禁用背景文字与边框
--m-text-title标题文字--m-text-default正文文字--m-text-sub次要文字--m-text-disabled禁用文字--m-border边框 / 分割线形状、排版与尺寸
:root {
--m-radius: 6px; /* 全局圆角(theme.shape.borderRadius) */
--m-font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;
--m-font-weight-medium: 500;
--m-size-default: 36px; /* 输入框 / 下拉 / 按钮等默认高度 */
--m-size-small: 28px;
--m-size-large: 48px;
}缓动与时长
组件的过渡动画统一使用这四个缓动函数与六个时长,做自定义动效时直接复用它们即可保持节奏一致。
| 变量 | 值 |
|---|---|
--m-ease-in-out | cubic-bezier(0.4, 0, 0.2, 1) |
--m-ease-out | cubic-bezier(0, 0, 0.2, 1) |
--m-ease-in | cubic-bezier(0.4, 0, 1, 1) |
--m-ease-sharp | cubic-bezier(0.4, 0, 0.6, 1) |
--m-dur-shortest ~ --m-dur-complex | 150ms / 200ms / 250ms / 300ms / 375ms |
--m-dur-entering / --m-dur-leaving | 225ms / 195ms(JS 读取,用于弹出面板) |
阴影
阴影直接取自 MUI 的 shadows.js。注意源码只定义了 0 / 1 / 2 / 3 / 4 / 6 / 8 / 12 / 16 / 24 这几档,其余档位不存在。
| 变量 | 用途 |
|---|---|
--m-shadow-0 ~ --m-shadow-24 | 通用 elevation |
--m-dialog-shadow | 对话框纸面(等于 --m-shadow-24) |
--m-dropdown-shadow | 菜单 / 浮层(Vuetify MD3 的 6dp 双层柔影) |
层级
| 变量 | 值 | 用途 |
|---|---|---|
--m-z-modal | 1300 | 模态层(Dialog / Drawer) |
--m-z-menu | 1301 | 菜单 / 下拉面板 |
--m-z-tooltip | 1500 | 文字提示 |
--m-z-toast | 1600 | Toast(最顶层) |
覆写令牌
在业务样式里重新声明同名变量即可,不需要 !important,也不需要修改组件库源码:
/* 把品牌主色换成青色系 */
:root {
--m-primary: #0f766e;
--m-primary-hover: #115e59;
--m-primary-light: #14b8a6;
--m-primary-rgb: 15 118 110;
}或者做一个作用域内的局部主题:
/* 只在这块区域里换掉圆角与主色 */
.brand-panel {
--m-radius: 12px;
--m-primary: #7c3aed;
--m-primary-rgb: 124 58 237;
}深色模式
暗色令牌定义在 :root[data-theme='dark'] 上,因此只需要在根元素(或任意局部容器)上挂一个属性:
// 跟随系统
const dark = window.matchMedia('(prefers-color-scheme: dark)').matches
document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light')// 手动切换
function toggleDark(on: boolean) {
document.documentElement.setAttribute('data-theme', on ? 'dark' : 'light')
}暗色下的取值变化
暗色模式并不是简单地把颜色压暗:语义色会切换为 MUI dark palette 的对应值(例如 --m-primary 从 #1976d2 变成 #90caf9),-contrast 变成深色文字,阴影的 alpha 会加重。业务侧不要硬编码浅色态的值。
与框架主题联动
本站在用 VitePress,它的深色模式类名是 html.dark,而组件库认的是 data-theme="dark"。站点的做法是在 Layout.vue 里监听 isDark 并同步属性,让文档站里的真实组件跟随站点外观切换 —— 这是一种通用做法,任何框架都可以照搬。
组件级变量
除全局令牌外,部分组件会把自己的 prop 下发给局部变量,方便在不改动 prop 的情况下做样式覆盖:
| 变量 | 来源 | 含义 |
|---|---|---|
--m-control-radius | Input / Select / DatePicker 的 radius | 触发区圆角 |
--m-panel-radius | Select / DatePicker / Dropdown 的 panelRadius | 弹出面板圆角 |
--m-dialog-radius | Dialog 的 radius | 对话框圆角 |
--m-divider-color / --m-divider-size / --m-divider-gap | Divider 的 color / size / gap | 分割线颜色 / 粗细 / 间距 |
--m-slider-percent | Slider | 已填充行程百分比 |
--m-slider-rail-h / --m-slider-thumb | Slider 的 trackSize / thumbSize | 轨道粗细 / 拇指直径 |
--m-ripple-duration / --m-ripple-initial-scale | v-ripple 的 duration / initialScale | 涟漪时长 / 起始缩放 |
--m-toast-duration / --m-toast-offset | Toast | 自动关闭时长 / 角位堆叠间距 |