Skip to content
返回设计中心

设计令牌与组件架构

跨平台可扩展的令牌管线、命名约定与组件组合策略。

设计令牌进阶

为什么

硬编码颜色和间距会导致主题漂移,使白标无法实现。设计令牌将决策集中为命名值,支持暗色模式、多品牌主题,以及从单一真源实现跨平台一致(Web + iOS + Android)。

Tokens Studio(原 Figma Tokens)有 50 万以上安装量,W3C 设计令牌格式模块即将成为候选推荐。令牌从单一来源实现暗色模式、多品牌主题和平台一致性。

何时使用

当有 2 个以上主题、跨平台发布或需要设计-工程同步且无 Figma 到代码漂移时引入令牌。从颜色 + 间距开始,后续加排版和动效。

如何做

1. 定义令牌分类 — 按原始(color)、语义(color.action.primary)、组件(button.bg.primary)分组 2. 选择格式 — Style Dictionary 多平台输出(CSS 变量、JS、Swift、Kotlin) 3. 编写源 — Figma 中 JSON 或 Tokens Studio,与代码一起在 git 中版本化 4. 构建管线 — style-dictionary build 输出 dist/tokens.css、tokens.ts、tokens.swift 5. 接入组件 — 组件引用 var(--color-action-primary),绝不使用原始 hex 6. 添加主题切换 — 在 <html> 上切换 data-theme 属性加载不同令牌集 7. 校验 — stylelint-declaration-strict-value 强制 CSS 中无硬编码值

示例

// tokens/color.json(Style Dictionary 源) { "color": { "brand": { "primary": { "500": "#6366f1", "600": "#4f46e5" } }, "action": { "primary": { "value": "{color.brand.primary.500}", "type": "color" }, "hover": { "value": "{color.brand.primary.600}", "type": "color" } } } } // config.js — Style Dictionary const StyleDictionary = require("style-dictionary"); StyleDictionary.extend({ source: ["tokens/**/*.json"], platforms: { css: { transformGroup: "css", buildPath: "dist/", files: [{ destination: "tokens.css", format: "css/variables" }]}, ts: { transformGroup: "js", buildPath: "dist/", files: [{ destination: "tokens.ts", format: "javascript/es6" }]} } }).buildAllPlatforms(); /* dist/tokens.css(生成) :root { --color-action-primary: #6366f1; --color-action-hover: #4f46e5; } */ // Button.css — 引用令牌,绝不使用原始值 .btn-primary { background: var(--color-action-primary); } .btn-primary:hover { background: var(--color-action-hover); }

常见问题

  • ⚠令牌层级过多 — 每个值都有原始 + 语义 + 组件三层,产生 500+ 无人使用的令牌
  • ⚠令牌未导出到所有平台 — Web 用 CSS 变量但 iOS 用硬编码颜色,漂移回归
  • ⚠重命名令牌破坏所有使用者 — 无 codemod,团队永久保留废弃别名
  • ⚠主题覆盖优先级战争 — 满地 !important,因为组件样式压过 :root 令牌

最佳实践

  • ✓最多 3 层:原始 → 语义 → 组件,仅在证明复用时才加组件层
  • ✓CI 中生成平台输出 — tokens.css 与 tokens.swift 不一致时构建失败
  • ✓为令牌重命名写 codemod(jscodeshift)— 在重命名同一 PR 中运行
  • ✓主题覆盖放在 :root[data-theme='dark'] — 绝不在组件 CSS 内覆盖

常见问题解答

令牌应该有几层?

最多三层:原始(color.blue.500)→ 语义(color.action.primary)→ 组件(button.bg)。仅在证明复用时加组件层,否则会有 500+ 闲置令牌。

Style Dictionary 和 Tokens Studio 用哪个?

互补:Tokens Studio 在 Figma 编写令牌导出 JSON;Style Dictionary 将 JSON 编译为 CSS 变量、JS、Swift、Kotlin。管线中两者都用。

如何重命名令牌而不破坏使用者?

写 jscodeshift codemod 更新所有引用,在重命名同一 PR 中运行。保留废弃别名一个发布周期后删除。

为什么暗色覆盖需要 !important?

因为组件 CSS 优先级压过 :root 令牌。把覆盖移到文档级 :root[data-theme='dark'],绝不在组件 CSS 内。

如何保持 Web 和 iOS 令牌同步?

CI 中从单一 JSON 源生成两平台输出——tokens.css 与 tokens.swift 不一致时构建失败。绝不手改平台输出。