设计系统 · · 阅读约 12 分钟
语义化令牌:2026 年构建设计系统唯一合理的方式
仅有别名是不够的。你需要一套能够经受深色模式、主题化和多品牌考验的语义层级。以下是如何从基本原则出发——而不是从工具出发——来构建它。
我见过设计系统因为各种原因而消亡。缺乏治理。团队人员流动。工程师只部分采用。但在过去两年里,我在那些崩溃最快的系统中发现了一个反复出现的模式:它们的令牌是扁平的,没有语义,只是看起来有条理,实际上并非如此。
一个包含 200 个名为 --color-blue-500、--color-blue-600 等 CSS 变量的文件,并不是一个设计系统。它只是换了个名字的调色板。而当支持深色模式、第二个品牌或低视力无障碍主题的需求到来时,这个文件就会成为一个严重的问题。
行之有效的三层层级
我在所有企业项目中使用的模型有三个不同的层级,各自承担独立的职责,并遵循清晰的依赖规则。
第 1 层——基础令牌(Primitives)。 这些是原始值:精确的颜色、尺寸、字体、时长。它们不携带任何语义。它们是系统的原始词汇。基础令牌从不直接在组件中使用——它们存在的唯一目的是被下一层引用。
第 2 层——语义令牌(Semantic tokens)。 这是魔法发生的地方。语义令牌将基础令牌映射到界面含义。它们描述的不是一种颜色——而是一种功能:--color-background-default、--color-text-primary、--color-border-subtle。在深色模式下,--color-background-default 的值会改变,但所有使用该令牌的组件都会自动更新——无需改动任何一个组件文件。
第 3 层——组件令牌(Component tokens)。 专属于单个组件或模式。--button-primary-background 指向 --color-action-primary,而后者又指向当前主题对应的正确基础令牌。对于小型系统,这一层是可选的,但在多品牌场景下则不可或缺。
缺乏语义的别名所带来的问题
许多团队实现了看起来像三层系统、实际上只有一层深的东西。像 --brand-primary: var(--color-blue-600) 这样的别名并不是语义令牌——它只是一个别名。它没有描述界面中的某种功能;它只是给一个特定的颜色起了个更短的名字。
如果我必须解释一个令牌是做什么的,那它的名字就起错了。
当你尝试构建一个替代主题时,区别就一目了然了。如果一个按钮使用 --brand-primary 作为背景,那么当第二个品牌以红色为主色时会发生什么?正确的语义令牌是 --color-action-primary-background:它描述的是功能和角色,可以在任何主题中映射到任何基础令牌而不会破坏任何东西。
实用的命名结构
我使用的命名约定遵循以下模式:类别——属性——变体——状态。并非每个部分都总是需要,但顺序始终不变。
--color-background-default——类别:color,属性:background,变体:default--color-text-on-primary——位于主色背景元素之上的文本--color-border-focus——焦点状态下的边框(用于 WCAG 无障碍)--size-spacing-md——中等尺度的间距--duration-interaction-fast——快速交互的时长
指导原则是:一个语义令牌的名称应当让设计师和开发者都能读懂,无需任何额外背景。
无需全面覆盖的深色模式
语义层级的实际回报在深色模式上体现得最为明显。你不需要用数百个例外去覆盖每一个单独的 CSS 变量,只需重新定义语义令牌与基础令牌之间的映射。
组件不会改变——它们始终引用同一个语义令牌。深色主题只是第 2 层的一个替换层,而不是对组件 CSS 的重写。采用这种方法,在一个包含 60 个组件的系统中,深色主题的 CSS 不到 80 行。
生产环境中的多品牌
在 Exein 项目中,我必须在同一套组件系统上管理三个视觉识别差异很大的品牌。解决方案是以品牌中立的方式构建语义令牌——它们描述的是功能,而不是身份——并为每个品牌编写独立的主题文件。
一个设计良好的语义令牌并不知道自己属于哪个品牌。它只知道自己需要在界面中做什么。
实际结果是:添加第四个品牌只用了不到半天时间。创建一个基础令牌文件,将其映射到现有的语义令牌,验证 WCAG 对比度。组件零改动。
2026 年的工具
Token Studio for Figma 仍然是连接设计与开发的标杆工具。Amazon 的 Style Dictionary 是将令牌分发为 CSS、JSON、Swift 和 Kotlin 最灵活的工具。但工具的选择要在架构的选择之后。一个设计糟糕的系统,不会因为换了软件就变成好系统。
