设计令牌是设计系统从文档走向工程的关键一步。本文从命名分层、语义映射、多主题治理、工具链同步、版本管理与团队协作等角度,拆解设计令牌如何真正落地,而不是停留在一次性的变量替换。

一个设计系统最容易断裂的地方,不在组件库的视觉稿,而在“设计稿上的颜色”到“代码里的值”之间那条通道。设计师改了品牌色,开发在几十个文件里搜索旧色值;产品要做暗色模式,发现颜色写死在组件内部;新来的工程师问“这个灰色该用哪个”,没有人能给出确定答案。设计令牌(Design Tokens)就是为了解决这条通道而存在的:它把颜色、字号、间距、圆角、阴影、动效时长等最小决策单位抽出来,命名为可被设计和代码共同引用的变量。

但设计令牌真正的难点,从来不是“把颜色变成变量”,而是让它在一段时间内保持稳定、可扩展、可治理。下面从结构、命名、映射、主题、工具链和协作几个层面展开。

令牌不是一个文件,而是一套三层结构

很多团队第一次做令牌,会直接建一个 colors.json,把品牌色、灰色、语义色全部混在一起。这种结构在单主题、小项目里能跑,一旦遇到暗色模式、多品牌或组件扩展,就会迅速失控。更可持续的做法是分成三层。

第一层是原始值(Primitive)。它只描述“这是什么颜色”,不描述用途。比如 blue-500gray-100space-4radius-2。这一层不含任何业务语义,相当于一套调色盘和尺度表。

第二层是语义令牌(Semantic)。它描述“这个值用在哪里”。比如 text-primarysurface-raisedborder-dangeraction-hover。这一层是设计与代码之间的契约,组件只引用这一层。

第三层是组件令牌(Component)。它描述“某个组件在某个状态下的具体取值”。比如 button-primary-bg-defaultinput-border-focusmodal-shadow。这一层可以覆盖语义令牌,用于组件级微调。

层级

命名关注点

示例

谁维护

原始值

色相、明度、尺度

blue-600space-4

设计系统核心团队

语义令牌

用途、角色

text-secondarysurface-sunken

设计系统 + 设计工程

组件令牌

组件、状态

button-danger-bg-hover

组件维护者

三层结构的好处是:品牌更新只需改原始值和语义映射;暗色模式只需替换语义令牌的取值;组件升级不影响底层色板。层级越清晰,后期治理成本越低。

命名决定了令牌能不能被用对

令牌命名是设计系统里最容易被低估的工作。名字如果只描述外观,使用者就要靠记忆去猜;名字如果描述用途,使用者就能按意图查找。命名应遵循几条原则。

  • 用角色,不用色相。text-danger 比 red-500 更稳定,因为品牌色可能变,语义不变。

  • 用层级,不用具体位置。surface-raised 比 card-bg 更通用。

  • 用状态,不用临时词。hoverfocuspresseddisabled 是固定后缀。

  • 用尺度,不用魔法数字。space-4 对应一个间距刻度,而不是 margin-13px

  • 用英文小写加连字符。保持跨语言、跨工具的一致性。

一个常见的命名模板是:

{类别}-{角色}-{属性}-{状态}

例如:

text-primary-default
text-primary-disabled
surface-raised-default
border-danger-focus
button-primary-bg-hover

命名不必追求绝对完整,但要保证同一类令牌遵循同一模式。团队可以接受“有点长”,但不能接受“同一种东西有三种叫法”。命名混乱会让令牌库迅速失去权威,开发宁愿写死数值。

语义映射是设计系统的核心资产

原始值只是原料,真正决定体验一致性的是语义映射。所谓映射,就是规定“哪个原始值在什么角色下被使用”。这一步做得好,主题切换、品牌换肤、暗色模式都只是替换映射表,而不是重做界面。

假设有一套中性色:

原始值

亮度

亮色模式角色

暗色模式角色

gray-0

最亮

页面背景

gray-50

很亮

卡片背景

gray-200

偏亮

分隔线

边框

gray-500

中间

辅助文字

辅助文字

gray-700

偏暗

正文

gray-900

很暗

标题

gray-950

最深

页面背景

映射表应该由设计系统团队维护,并且有明确的“不要直接使用原始值”规则。组件代码里出现 gray-200 就是一种信号,说明语义层缺失或不够用。发现这种情况,应该补语义令牌,而不是允许例外长期存在。

多主题与暗色模式:令牌真正发挥价值的地方

暗色模式不是把颜色反过来,而是重新定义每个语义角色在暗背景下的取值。设计令牌让这件事从“逐个组件改样式”变成“替换一张映射表”。

亮色模式下,surface-raised 可能是白色,靠阴影表达层级;暗色模式下,阴影几乎不可见,层级要靠表面亮度差。于是 surface-raised 在暗色模式中可能变成比页面背景更亮一阶的深灰。类似的还有:

  • text-primary:亮色模式接近黑,暗色模式接近白但略降亮度,避免光晕。

  • border-default:亮色模式偏浅,暗色模式需要提高对比度。

  • action-primary:亮色模式用较深的品牌色配白字,暗色模式可能要提亮品牌色以保持对比。

  • shadow-overlay:暗色模式中可能需要替换为边框或内发光。

多品牌场景同理。品牌 A 的主色是蓝,品牌 B 的主色是绿,但 action-primarytext-linkfocus-ring 这些角色名不变,只是映射到不同的原始值。组件代码不需要知道品牌是谁。

工具链:令牌要能被设计工具和代码同时消费

设计令牌如果只存在代码里,设计师改稿时仍然可能用错颜色;如果只存在设计工具里,开发仍然要手动转换。理想状态是单一数据源,向两端同步。

常见的做法是用 JSON 或 YAML 作为源文件,通过构建脚本生成多端产物:

tokens/
primitive.json
semantic.light.json
semantic.dark.json
component.json

构建后输出:

  • CSS 自定义属性:--text-primary

  • 预处理器变量:$text-primary

  • JavaScript/TypeScript 常量:tokens.text.primary

  • iOS/Android 资源文件

  • 设计工具可导入的变量集

这一步的工程化程度,决定了令牌能不能被日常使用。如果每次改令牌都要手动通知三端,团队很快就会绕开它。

版本管理与变更沟通

设计令牌是公共契约,变更会影响所有使用方。因此它需要像 API 一样管理版本。

变更类型

示例

版本影响

沟通方式

新增令牌

增加 surface-sunken

次版本

发布说明

修改取值

text-secondary 调深

补丁或次版本

视觉回归 + 说明

重命名

card-bg 改为 surface-raised

主版本

迁移指南 + 弃用期

删除令牌

移除废弃变量

主版本

提前公告

新增主题

增加高对比主题

次版本

文档更新

重命名和删除是最危险的,因为它们会直接让组件报错或回退到默认值。稳妥做法是先并行保留旧名一段时间,在构建时输出警告,给使用方迁移窗口。令牌的废弃日志,应该像依赖库的 changelog 一样被认真对待。

团队协作:谁来决定令牌

设计令牌不是设计师或前端单方面的工作,它需要明确的角色分工。常见分工如下:

  • 设计系统负责人:决定令牌结构和命名规范。

  • 视觉设计师:提供原始值和语义映射建议。

  • 设计工程师:维护构建脚本、类型定义和文档。

  • 组件维护者:按需提出组件级令牌申请。

  • 产品团队:作为使用方反馈缺口,但不直接新增令牌。

新增令牌应该有门槛。不是每个“这个颜色和默认不一样”的需求都要变成令牌。可以先问三个问题:这个值是否会被复用?是否属于已有语义角色?是否能通过组合现有令牌解决?如果答案都是否,才考虑新增。令牌库越克制,越容易被信任。

落地检查清单

  • 是否区分了原始值、语义令牌和组件令牌三层?

  • 命名是否描述用途而非外观?

  • 组件是否只引用语义层和组件层,不直接引用原始值?

  • 亮色与暗色模式是否通过映射表切换?

  • 多品牌场景是否只替换映射,不改组件?

  • 令牌源文件是否单一,且能同步到设计工具与多端代码?

  • 是否有类型定义,拼错令牌能否被工具发现?

  • 变更是否有版本记录和迁移指南?

  • 是否定期清理废弃令牌?

  • 新成员能否在不问人的情况下找到正确令牌?

设计令牌的价值,不在于它让变量变多了,而在于它让决策变少了。设计师不必每次重新选色,开发不必猜测某个灰色是否合规,产品换主题时不必重做界面。它把“品牌语言”和“代码语言”对齐成同一套词汇,让设计系统从一份文档变成可执行的契约。做好这一步,组件库、暗色模式、多品牌和跨端一致性才有真正稳固的地基。

© 版权声明
演示站内容均来自互联网,如有侵权,请与我联系

文章不错?点个赞呗~