web design uiMay 29, 20269 min read

Design Tokens:真正的设计系统如何保持一致性

Design tokens 是什么,真实系统使用的三层模型(Shopify Polaris、IBM Carbon、GitHub Primer),如何命名,暗色模式主题化,以及何时 tokens 是过度设计。

By Boone
XLinkedIn
design tokens

Design Tokens:真正的设计系统如何保持一致性

Hex 色码是一个值。Token 是一个有名字的决策。设计系统由决策构成,而非数值。

这个区别就是全部意义所在。把 #0EA5E9 硬编码进十四个 Figma 组件,然后被要求做暗色模式,你就要面对一周的查找替换工作。把它命名为 color-interactive-primary,你只需改一个值,所有界面随之更新。这不是魔法,只是有名字的决策。

Design token 到底是什么

Design token 是一个存储设计决策的命名变量。它可以保存颜色、间距值、字体大小、圆角半径、阴影或时长。名字是契约。名字背后的值可以改变,而不会破坏任何使用该 token 的地方。

经典的无 token 方式是这样开始的:设计师为主按钮选择了 #1D4ED8,将其硬编码进按钮组件,然后把这个 hex 值复制到卡片、徽章和链接中。六个月后,品牌更新了。现在你面对的是一个随着每个组件数量线性增长的维护噩梦。

Tokens 反转了这一切。你命名决策(color-action-default),赋值一次,所有引用该 token 的地方保持同步。值是实现细节,名字才是系统。

让 tokens 发挥作用的三层结构

原始 tokens 只是变量。让 token 系统真正有用的是层级结构。每个值得研究的生产系统都使用三层结构。

层级别称存储内容示例
Primitive(原始层)Global、Base无语义的原始值color.blue.500 = #3B82F6
Semantic(语义层)Alias、Role映射到原始层的命名角色color.interactive.default = color.blue.500
Component(组件层)Specific组件范围的决策button.background.default = color.interactive.default

Primitives 是你的调色板。每一个蓝色、每一个间距步长、每一个圆角半径都以命名值的形式存在于此,不对使用场景做任何假设。你不应在组件中直接使用 primitives。

Semantic tokens 将角色映射到 primitives。Token color-surface-default 在亮色模式可能指向近白色,在暗色模式指向近黑色,而组件从不知道它获得的是哪个原始值。它只知道角色。

Component tokens 是最具体的。当一个组件需要有意区别于语义默认值的决策时,它才存在。危险按钮将背景指向 critical-feedback 角色,而不是默认的 interactive 角色。大多数组件不需要自己的 tokens,它们直接使用 semantic tokens。

体素图展示三层堆叠的 token 层级:原始比例尺、语义角色和组件决策。
体素图展示三层堆叠的 token 层级:原始比例尺、语义角色和组件决策。

为什么 tokens 胜过硬编码值

变更速度是显而易见的论点,但不是真正的论点。真正的论点是精确性。

当设计师交付一个充满原始 hex 色码的文件时,开发者根本不知道哪些是有意为之,哪些是误操作。#1A1A2E 是背景色,还是有人不小心吸取了错误图层的颜色?Tokens 消除了这种歧义。语义 token 名是随值一起传递的文档。

Tokens 也是 2026 年设计工具与代码之间的交付契约。Figma variables 直接映射到 CSS custom properties。在 Figma 文件中定义的 token 可以无需任何手动步骤地导出、提交并在代码中使用。当设计和实现双方使用相同的 token 名称时,两者之间的鸿沟就消失了。

对于进行无障碍设计工作的团队,tokens 增加了一层安全保障。你在一处审计语义调色板,就能保证无论哪个主题处于激活状态,color-text-default 相对于 color-surface-default 始终满足 4.5:1 的对比度要求。

真实设计系统如何组织 tokens

有三个系统值得了解:Shopify Polaris、IBM Carbon 和 GitHub Primer。它们对三层模型的处理方式各不相同,而这些差异很有启发性。

Shopify Polaris 将 primitives 保存在颜色比例尺中(从 color-sky-100color-sky-900),并将它们别名化为语义角色,如 --p-color-bg-fill-active。Component tokens 很少,大多数组件使用 semantic tokens。命名约定是角色在前、状态在后,在代码中读起来很自然,因为无需额外上下文就能知道 bg-fill-disabled 的用途。

Shopify Polaris token 参考页面,列出颜色 tokens 及其 CSS custom property 名称和值。
Shopify Polaris token 参考页面,列出颜色 tokens 及其 CSS custom property 名称和值。

在 polaris.shopify.com 上查看

IBM Carbon 在语义层上下了很深的功夫。它的颜色集包括明确的反馈 tokens(如 support-errorsupport-success)、交互状态 tokens,以及用于嵌套表面的层级 tokens(页面上面板上的组件,每一层都需要不同的表面值)。它更复杂,但 IBM 做的是企业软件,每一个嵌套状态都很重要。

IBM Carbon 设计系统颜色页面,展示映射到界面角色的语义颜色 tokens。
IBM Carbon 设计系统颜色页面,展示映射到界面角色的语义颜色 tokens。

在 carbondesignsystem.com 上查看

GitHub Primer 将其原始层公开为 "primitives",将语义层公开为 "functional tokens",在 primer.style 上有公开文档。Primer 的主题化让 GitHub 能够从单一组件集派发亮色、暗色、亮色高对比度和暗色低亮度四种主题。每个主题都是对相同 token 名称的不同值赋值。

这三者之间的模式是一致的:primitives 作为比例尺,semantic tokens 作为角色名称,主题化作为语义层的值交换。组件保持不变。


Brainy 帮助设计师构建可扩展的系统,而不是一次性界面。了解我们为创作者构建的内容,请访问 /creators


命名 tokens 而不失去理智

Token 命名会让团队崩溃。太泛化,名字毫无信息量。太具体,你得为每个组件写一个新 token。

一个有效的命名约定包含四个部分:类别、角色、变体和状态。你不会每次都用上全部四个,但这个结构能防止随意命名的混乱。

部分捕获内容示例
Category(类别)设计属性colorspacingradiusshadowfont
Role(角色)语义用途surfacetextborderinteractivefeedback
Variant(变体)子角色或修饰语primarysecondarydangersubtle
State(状态)交互条件defaulthoveractivedisabledfocus

以下是开发者实际使用的 CSS custom properties 形式的工作示例:

  • color-surface-default 设置默认页面背景
  • color-text-subtle 是对比度较低的次要文本
  • color-interactive-primary-hover 是主要操作的悬停状态
  • spacing-component-md 是组件的中等内部间距
  • radius-interactive 是可点击元素的圆角半径

两条规则能省去最多争论。永远不要在名字中编码原始值,因为 color-blue-500 无法说明角色。永远不要在 semantic 层按组件命名,因为 semantic 层里的 button-primary-color 意味着你完全跳过了语义层。

对于可扩展的字体系统,同样的约定适用,font-size-body-lg 永远优于 text-18px

体素插图展示一个 token 名称拆分为四个部分:类别、角色、变体和状态。
体素插图展示一个 token 名称拆分为四个部分:类别、角色、变体和状态。

一套 token,亮色与暗色模式

暗色模式是 token 系统回报最明显的地方。如果你按角色命名了 tokens,暗色模式就是值的交换,而不是重新设计。

GitHub Primer 设计系统网站,其 functional tokens 从一套 token 集派发亮色、暗色和高对比度主题。
GitHub Primer 设计系统网站,其 functional tokens 从一套 token 集派发亮色、暗色和高对比度主题。

在 primer.style 上查看

机制很简单。你的 semantic token color-surface-default 指向一个 primitive,在亮色模式接近白色,在暗色模式接近黑色。使用它的组件从不改变。你通过在语义层交换值映射来切换主题。

CSS custom properties 让这一切变得机械化:

css
:root { --color-surface-default: #ffffff; --color-text-primary: #111827; } [data-theme="dark"] { --color-surface-default: #0f172a; --color-text-primary: #f8fafc; }

每个引用 var(--color-surface-default) 的组件现在都能响应主题属性,无需任何额外代码。Shopify Polaris、GitHub Primer 和 IBM Carbon 都在生产规模上使用这种模式。

失败模式是在组件中混用 semantic 和 primitive tokens。当组件直接引用 color-blue-600 而不是 color-interactive-primary 时,该组件就停止响应主题了。一个粗心的 primitive 引用会破坏整个模型。在组件代码中标记直接使用 primitive 的 lint 规则值得花时间配置。

理解颜色选择如何发挥作用给你提供了概念基础,而 tokens 给你提供了在每个主题中付诸实践的结构。

何时 design tokens 是过度设计

Tokens 增加了间接性。间接性有成本。对于何时值得付出这些成本,要诚实面对。

情况用 Tokens?原因
服务 3 个以上产品的设计系统共享 tokens 立即物有所值
单一产品,5 名以上设计师防止团队调色板漂移
单一产品,1-2 名设计师,积极迭代中也许仅用语义层,跳过 component tokens
营销网站,无组件库单一样式表改起来更快
3 个月内的原型或 MVP等设计稳定后再抽象
为现有系统添加暗色模式这正是 tokens 的用武之地

小团队没有 tokens 反而更快。一个追求产品市场契合的三人初创公司不需要三层层级结构。当你每两周就改变视觉方向时,一个 Figma 样式库就够了。

要避免的反模式是过早的语义命名。命名为 color-bluecolor-gray 的 tokens 增加了间接性但没有意义。要么用 color-surfacecolor-text 按角色命名,要么坚持使用 primitives,直到你有足够的组件来了解角色实际上是什么。

糟糕的 token 命名比没有 tokens 更糟。在语义层中命名为 button-color-for-the-checkout-page 的 token 是一个维护陷阱。命名规范不是可选项,它是 tokens 能够发挥作用的原因。

体素插图对比极简双 token 配置与过度工程化的多层塔。
体素插图对比极简双 token 配置与过度工程化的多层塔。

FAQ

Design tokens 会取代 Figma styles 吗?

不会,但会扩展它们。2023 年发布的 Figma variables 是 Figma 内部最接近的原生等价物,当你在两者之间共享命名约定时,它们会映射到代码 tokens。Figma styles 处理字体排版和颜色填充,而 variables 处理完整的 token 层级,包括状态和组件级决策。

没有设计系统,tokens 能用吗?

Tokens 在设计系统内部最有价值,但即使是单一产品也能从 CSS custom property 级别的语义命名中受益。你不需要一个正式的系统来停止硬编码 hex 值。

我应该用什么工具来管理 tokens?

对于小团队,Figma variables 加上 JSON 导出就足够了。对于较大的团队,Style Dictionary(开源,由 Amazon 出品)是标准构建工具。它接受 token JSON 结构,输出 CSS custom properties、iOS Swift 常量和 Android XML。Tokens Studio for Figma 是 Figma 和 Style Dictionary 之间流行的插件桥梁。

Component tokens 应该有多细粒度?

只需要足够细粒度即可。大多数组件可以直接使用 semantic tokens。当一个组件有意偏离语义层时,组件特定的 tokens 才有意义,比如破坏性操作按钮或具有不寻常表面的横幅。有疑问时,使用 semantic tokens,只在你发现自己在写例外情况时才创建 component tokens。

Tokens 只能处理颜色,还是也能处理间距和字体排版?

Tokens 适用于任何具有离散值的属性:颜色、间距、字体排版、圆角半径、盒阴影、动效时长、动效缓动和 z-index。最成熟的系统,如 IBM Carbon 和 Atlassian Design System,对所有这些都有 tokens。从颜色和间距开始,随着系统成熟再添加其他属性。

停止硬编码值

实际路径并不复杂:

  • 将你的 primitives 命名为比例尺
  • 将这些 primitives 映射到语义角色
  • 让每个组件使用 semantic tokens,永远不要直接使用 primitives
  • 从单一来源(Figma variables、JSON 文件或设计系统包)导出 token 值,让构建工具将其分发到 CSS、iOS 和 Android

你不需要三个月的迁移才能开始。选择一个组件,命名它的决策,感受一下当你改变一个值而看到所有东西更新时的不同。那种体验就是最好的论据。

更多设计系统相关内容,请查看 Brainy 的其他文章 /paper

Brainy helps designers build systems that scale, not one-off screens. See what we are building for creators.

Get Started

More from Brainy Papers

Keep reading