Skip to content

Token 架构

设计 token 分 3 层 + 组件。从下到上依次抽象:纯色彩学 → 品牌身份 → 使用意图 → 组件消费。每一层只往上暴露稳定接口,下层换实现不影响上层。

┌──────────────────────────────────────────────────────────────────┐
│ 4  ATOM  组件                                                     │
│    Button / Item / Badge / Navigation ...                        │
│    只引用 SEMANTIC,从不直接引用 BRAND / PALETTE                  │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│ 3  SEMANTIC  语义层  ·  tokens/semantic/dark.json (74 token)      │
│    "这个颜色用来做什么"                                            │
│    text-default / text-accent / surface-elevated /               │
│    state-hover / border-divider / hue-blue ...                   │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│ 2  BRAND ROLE  品牌角色  ·  tokens/brand/dark.json + brand.json   │
│    "这个颜色代表什么品牌身份"                                       │
│    brand-mark / brand-primary-* / brand-warning-* / brand-error-* │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│ 1  PALETTE  调色板  ·  tokens/core/color.hue.json + ...           │
│    "这个颜色长啥样"  —  纯色彩学,brand-agnostic                   │
│    lime / yellow / red / blue / purple / apricot ...11 hue       │
│    nature N-1..N-5 / bg-light/dark/solid / overlay / tooltip     │
└──────────────────────────────────────────────────────────────────┘

Layer 1 · Palette 调色板

纯色彩学。 不带任何业务含义。位置:tokens/core/

11 个 hue 色板

每个 hue 有 8 个 stop(4 solid + 4 alpha tint):

Palette代表色(2 号位)用途线索
red#EB5147警示 / 删除
apricot#F57D42暖橙
orange#F3A237
yellow#DABF22提示
lime#A7CD45黄绿(当前 brand-primary
green#4BC950通过 / 在线
teal#18CD91青绿
blue#79B5FA信息 / 链接
indigo#8C96F9
purple#BB9AFB
magenta#F586DC品红

每个 hue 的 CSS 变量:--mc-{name}-{stop},例:--mc-lime-2 --mc-red-t8

完整调色板见 色彩 Color

中性 / 背景 / 装饰

  • mc-n-1..mc-n-5:前景中性色(透明白阶 18% → 100%)
  • mc-bg-light-1..4 / mc-bg-dark-1..4:背景叠加(白蒙层 / 黑蒙层)
  • mc-bg-solid-1..5:背景实色(页面 / 容器 / 浮层)
  • mc-overlay-* / mc-tooltip / mc-border-light:杂项

⚠️ palette 层名字不带任何业务暗示lime 是黄绿色这个事实;它"恰好"是美餐当前的产品主色,但 palette 不知道这件事。

Layer 2 · Brand Role 品牌角色

业务身份。 把 palette 跟"品牌承担什么角色"绑起来。位置:tokens/brand/

Token当前映射含义
mc-brand-mark#6EB92C 直写美餐 logo 标识色(不基于 palette)
mc-brand-primary-*→ lime-*产品主色(链接 / 选中 / 强调)
mc-brand-warning-*→ yellow-*警告
mc-brand-error-*→ red-*错误 / 删除

未来要加可加:mc-brand-info / mc-brand-success / mc-brand-neutral,按需。

为什么这一层存在

因为 palette 跟 brand 是两个概念,不该绑死。例子:

想把产品主色从 lime 换成 blue。

如果没有 brand 层,要把 atom 里所有 --mc-lime-2 改成 --mc-blue-2(几十处),而且 lime 这个名字也变得名不副实。

有 brand 层,只改 tokens/brand/dark.json 8 行

diff
 "primary": {
-  "1":   { "value": "{mc.lime.1}" },
-  "2":   { "value": "{mc.lime.2}" },
-  "3":   { "value": "{mc.lime.3}" },
-  "4":   { "value": "{mc.lime.4}" },
+  "1":   { "value": "{mc.blue.1}" },
+  "2":   { "value": "{mc.blue.2}" },
+  "3":   { "value": "{mc.blue.3}" },
+  "4":   { "value": "{mc.blue.4}" },
   ...
 }

pnpm build:tokens 一跑——所有组件主色变蓝,atom CSS 一行不改

Layer 3 · Semantic 语义层

使用意图。 atom 描述"我在用啥"——背景、文字、状态、描边。位置:tokens/semantic/dark.json,74 个 token,7 组:

例子用途
text-*text-default text-accent text-warning-hover text-on-solid前景文字(含交互态 stepping)
surface-*surface-page surface-elevated surface-overlay容器底色(5 个 elevation 级别)
solid-*solid-accent solid-warning-pressed实色按钮背景(含 hover/pressed)
state-*state-hover state-pressed state-selected state-on-focus交互态叠加
btn-bg-*btn-bg-background btn-bg-trans-hover按钮 type 的 bg 抽象
border-*border-default border-divider border-focus描边
hue-*hue-blue hue-purple hue-errorBadge / Tag 装饰色(12 色 + disabled)

命名约定

mc-{layer-prefix}-{name}[-{state}]
  • state 后缀:-hover / -pressed / -disabled
  • 没 state 后缀 = default 态
  • 大部分 atom 都 4 态全套,少数(如 hue-*)只有 1 态

atom 引用规范

✅ atom CSS 只用 semantic:

css
.mc-btn {
  background: var(--mc-solid-accent);
  color: var(--mc-text-on-solid);
}
.mc-btn:hover {
  background: var(--mc-solid-accent-hover);
}

❌ atom CSS 不要直接引用 palette / brand role:

css
/* DON'T */
.mc-btn { background: var(--mc-lime-3); }
.mc-btn { background: var(--mc-brand-primary-3); }

如果发现某个用途 semantic 没覆盖,先回去加 semantic token,再回 atom 引用——不要走捷径绕过这层。

Layer 4 · Atom 组件

实际渲染层。CSS 引用 semantic,靠 props / state class 切换不同 semantic 变量。

例:Item.vue 里:

css
.mc-item--active-off { --mc-item-fg: var(--mc-text-default); }
.mc-item--active-green { --mc-item-fg: var(--mc-text-accent); }
.mc-item--active-white { --mc-item-fg: var(--mc-text-strong); font-weight: 500; }

.mc-item:hover { --mc-item-bg: var(--mc-state-hover); }

active 三态对应三套 semantic 引用,hover 切 state 层——整个 atom 不知道 lime / red / brand-primary 是什么颜色

切换 / 扩展 token 的标准流程

场景改哪一层
换产品主色(lime → blue)Brand Role(8 行 JSON)
增加一个新装饰色(如 cyan)Palette + Semantic.hue(两层都加)
调整某个 atom 的 hover 配色Semantic(找对应 token)
一个 atom 缺颜色用先在 Semantic 加 token, 在 atom 引用
切 light mode(v1.5)tokens/semantic/light.json(74 个 key 对到 light 等价)+ Style Dictionary 配置 mode 输出
加新组件类型(如 Tag)引用现有 semantic;缺什么补什么到 semantic 层

工具链

  • Style Dictionary v5 把所有 tokens/**/*.json 合并并输出 build/css/tokens.css
  • 运行:pnpm build:tokens(dev/build 前自动跑一次)
  • 配置:style-dictionary.config.js(极简,所有 token 一起 dump)
  • Light mode 多 selector 输出留待 v1.5 配 SD 转换器

Token 总数(截至 2026-05-15)

文件token 数
Palettetokens/core/ 9 个 JSON约 130
Brand Roletokens/brand/ + tokens/brand.json25
Semantic (dark)tokens/semantic/dark.json74
Semantic (light)tokens/semantic/light.json0(待填)

CSS 变量总输出:约 261 行。