设计令牌格式模块 2025.10

最终社区组报告

本版本:
https://www.w3.org/community/reports/design-tokens/2025.10/
最新发布版本:
https://www.designtokens.org/TR/2025.10/format/
编辑:
Louis Chenais
Kathleen McMahon
Drew Powers
Matthew Ström-Awn
Donna Vitan
作者:
Daniel Banks
Mike Kamminga
Ayesha Mazrana (Mazumdar)
James Nash
Adekunle Oduye
Kevin Powell
反馈:
GitHub design-tokens/community-group (拉取请求, 新问题, 开放问题)

摘要

本文档描述了一种用于在不同工具之间交换设计令牌的文件格式技术规范。

本文档状态

本规范由 Design Tokens 社区小组发布。它不是 W3C 标准,也不属于 W3C 标准进程。 请注意,根据 W3C 社区最终规范协议 (FSA) ,还适用其他条件。 了解更多关于 W3C 社区与业务小组的信息。

本章节描述了本文档在发布时的状态。其他文档可能会取代本文件。当前 W3C 社区小组报告及本报告的最新修订可在 W3C 社区小组报告索引 https://www.w3.org/community/reports/中找到。

本文档由 DTCG 根据 W3C 流程中的定义,作为 候选推荐 发布。对本草案的贡献受 社区贡献者许可协议 (CLA) 的约束,具体见 W3C 社区小组流程

虽然并非 W3C 推荐标准,此分类旨在说明:经过广泛共识建设后,该规范可直接用于实现。

本规范被认为是稳定的。后续更新将在后续规范中继续提供。

建议通过 GitHub Issues 对本规范进行讨论。

1. 一致性

除了被标记为非规范性的部分之外,本规范中的所有编写指南、图示、示例和注释都是非规范性的。规范中的其他内容均为规范性条款。

本文档中的关键字 MAYMUSTMUST NOTSHOULDSHOULD NOT 应按照 BCP 14 [RFC2119] [RFC8174] 的说明进行解释,且仅当这些关键字全大写时,如本例所示。

2. 简介

本节为非规范性内容。

设计令牌是一种在不同平台间表达设计决策的方法论,使其能够在不同的领域、工具和技术之间共享。它们有助于在组织中建立通用的设计术语。

目前,越来越多的设计系统维护者和使用者工具集成了设计令牌功能,或者受益于设计令牌能力的发展,如下所示:

设计系统团队通常希望将这些工具进行集成,从而使设计令牌数据能在设计和开发工具之间流通。

例如:

虽然许多工具现在都提供了访问设计令牌的API,或能够导出设计令牌文件,但这些功能都是工具特定的。因此,设计系统团队需要创建和维护自己的“粘合”代码或工作流。此外,如果团队需要迁移到不同工具,还需要更新这些集成代码。

本规范通过定义一种表达设计令牌数据的标准文件格式,旨在提升工具间的互操作性,降低设计系统团队集成各类工具的工作负担。

3. 术语

以下定义聚焦于规范的技术细节,面向如设计工具厂商等实现者。为设计师和开发者准备的定义参见designtokens.org

3.1 (设计)令牌

(设计)令牌是与一个可读名称相关联的信息,至少包括一个名称/数值对。

例如:

该名称可以关联更多的令牌属性

3.2 (设计)令牌属性

与令牌名称相关联的信息。

例如:

工具和设计系统可以根据需要添加更多的元数据,以扩展该格式。

3.3 设计工具

设计工具用于创建和编辑视觉设计。

例如:

3.4 转换工具

设计令牌转换工具用于将令牌数据从一种格式转换为另一种格式。

例如:

3.5 文档工具

文档工具用于记录设计令牌的使用。

例如:

3.6 类型

令牌的类型是对其值的一种预定义分类。

例如:

令牌工具可以利用类型推断令牌的用途。

例如:

3.7 分组

分组是归属于某一特定类别的令牌集。

例如:

分组是任意的,工具 SHOULD NOT (不应)用其推断设计令牌的类型或用途。

3.8 别名(引用)

设计令牌的值可以引用另一个令牌。同一个实际值可以被多个名称或别名拥有。

下述 Sass 示例说明了此概念:

$color-palette-black: #000000;
$color-text-primary: $color-palette-black;

$color-text-primary 的值为 #000000,因为 $color-text-primary 引用 $color-palette-black。我们也可以说 $color-text-primary$color-palette-black别名

3.9 复合(设计)令牌

值由多个具名子值组成的设计令牌。复合令牌适合那些总是同时应用的一组紧密相关的样式属性。例如,一个排版样式可以由字体名、字号、行高和颜色组成。

这是一个复合阴影令牌的示例

{
  "shadow-token": {
    "$type": "shadow",
    "$value": {
      "color": {
        "$type": "color",
        "$value": {
          "colorSpace": "srgb",
          "components": [0, 0, 0],
          "alpha": 0.5,
          "hex": "#000000"
        }
      },
      "offsetX": { "value": 0.5, "unit": "rem" },
      "offsetY": { "value": 0.5, "unit": "rem" },
      "blur": { "value": 1.5, "unit": "rem" },
      "spread": { "value": 0, "unit": "rem" }
    }
  }
}

4. 文件格式

设计令牌文件是 JSON(https://www.json.org/)格式的文件,需符合本规范定义的结构。

选择 JSON 作为交换格式的原因如下:

4.1 媒体类型(MIME 类型)

通过 HTTP / HTTPS 传输设计令牌文件,或在需要指定媒体类型(即原 MIME 类型)的其他场景下,设计令牌文件SHOULD(应)使用如下 MIME 类型:

但由于每个设计令牌文件都是合法 JSON 文件,也MAY(可以)使用 JSON 媒体类型:application/json。建议优先使用前者更具体的媒体类型。

能够打开设计令牌文件的工具MUST(必须)同时支持上述两种媒体类型。

4.2 文件扩展名

在本地文件系统保存设计令牌文件时,使用不同的文件扩展名有助于在文件浏览器中识别。还便于关联文件图标及首选打开应用。规范推荐以下文件扩展名:

前者更简洁,但在该格式尚未被广泛支持时,后者便于用常用 JSON 编辑器直接打开设计令牌文件。

能够打开设计令牌文件的工具MAY(可以)在打开文件对话框中只显示这些扩展名的文件。建议同时为用户提供打开其他扩展名文件的选项(如“显示所有文件“等)。

能够保存设计令牌文件的工具SHOULD(应)在保存时自动添加推荐扩展名之一。

编辑者注: JSON schema

工作组目前正在探索为规范增加 JSON Schema 的可行性。

编辑者注: JSON 文件大小限制

有厂商提出了有关 JSON 文件大小限制的担忧,工作组将持续收集关于 JSON 格式局限的反馈。

5. 设计令牌

5.1 名称和值

带有 $value 属性的对象即为一个令牌。因此,$value 是本规范中的保留字,意味着不能以 "$value" 作为令牌名。父对象的键即为令牌名。

令牌名称必须是 [RFC8259] 所定义的有效 JSON 字符串。

因此,上述示例定义了一个具有如下属性的设计令牌:

名称和值都是必需的。

令牌名称区分大小写,因此下例中同组下只大小写不同的2个令牌是合法的:

然而,一些工具可以在向其他语言导出或向用户展示名称时需转换名称,因此仅大小写不同的令牌名可能导致导出中出现重复且不理想。例如,将这些令牌转换为 Sass 代码时会导致如下问题:

工具可以在令牌名仅大小写不同时报出警告。

5.1.1 字符限制

本格式定义的所有属性均以美元符号($)为前缀。本规范后续的新属性也会使用该约定。因此,令牌和分组不得$字符开头。

此外,由于令牌别名中使用的语法,令牌和分组名称中不得包含以下字符:

  • {(左花括号)
  • }(右花括号)
  • .(点号)

5.2 附加属性

虽然 $value 是令牌的唯一必需属性,但还可以增加如下附加属性:

5.2.1 描述

可以通过可选的 $description 属性添加关于令牌用途的纯文本说明。工具可以以多种方式使用描述信息。

例如:

  • 风格指南生成工具可以将描述文本与令牌视觉预览一起展示
  • IDE可以在自动补全时将描述作为提示气泡显示(类似 API 文档)
  • 设计工具可以将描述作为令牌的提示或标签在可选令牌的地方显示
  • 转换工具可以将描述渲染为导出变量或常量旁的源代码注释

$description属性的值必须是纯 JSON 字符串,例如:

5.2.2 类型

设计令牌总有明确类型,以便工具可靠地解释其值。

可通过可选的 $type 属性指定令牌类型。如果未在令牌上设置 $type 属性,则其类型必须按如下规则确定:

  • 若令牌值是一个引用,则类型为被引用令牌的解析类型。
  • 否则,若父分组有 $type 属性,则类型取最近的父分组的 $type 属性。
  • 否则,若所有父分组都没有 $type 属性,则无法确定类型,此令牌必须视为无效。

工具不得通过检查值内容来猜测类型。

$type 属性可在不同层级设置:

  • 分组级
  • 令牌级

$type 属性必须为纯 JSON 字符串,其值须为本规范类型定义中指定的值之一。该值区分大小写。

例如:

5.2.3 扩展

可选的 $extensions 属性为对象,工具可以在此为设计令牌添加专有的、用户、团队或厂商相关数据。每个工具必须使用带厂商标识的键,其值可以是任意合法 JSON 数据。

  • 键名选择避免与其它厂商数据冲突,推荐采用反向域名标识法
  • 处理设计令牌文件的工具必须保留所有自己不识别的扩展数据。例如,含有 A 工具扩展数据的令牌文件在 B 工具中打开并保存后,仍必须保留原始的 A 工具扩展数据。

为保持不同支持该格式工具间的互操作性,团队与工具将扩展数据仅用于非核心的可选元数据,不应包含理解令牌值所必需的信息。

鼓励工具厂商尽量公开扩展数据的规范,方便其他工具兼容,将热门扩展纳入将来的标准特性。

编辑者注: 扩展部分

扩展部分不限于厂商,所有令牌使用者均可在此添加自定义数据以满足自有需求。

5.2.4 弃用

$deprecated 属性可以用于标记某令牌为已弃用,并可选解释原因。弃用原因包括但不限于:

  • 设计系统未来会移除此令牌
  • 立即移除可能会破坏现有支持
  • 不建议今后使用此令牌
说明
true 该令牌已弃用(无具体说明)。
字符串 本令牌已弃用,且该字符串为说明。
false 该令牌未弃用(可用于覆盖分组默认值)。

工具开发者可以对说明字符串(如包含别名)进行增强。例如,解析该令牌,并在 UI 中链接到文档、代码或可视化替代令牌。例如,“建议改用 {button.activeBorder}” 可作为 JS 输出:

6. 分组

分组将设计令牌组织为逻辑集合,并为令牌文件提供分层结构。分组是任意的,工具 SHOULD NOT 不应使用分组来推断设计令牌的类型或用途。

6.1 分组结构

分组被标识为不包含 $value 属性的 JSON 对象。分组 MAY 可以包含:

重要说明:存在 $value 属性的对象明确被识别为令牌。如果一个对象同时包含 $value 和子令牌/子分组,则形成无效结构,因为该对象不能同时既是令牌又是分组。工具 MUST 必须将此报告为错误。

6.2 分组中的根令牌

分组 MAY 可以在子令牌和嵌套分组之外包含一个 根令牌。根令牌为该分组提供基础值,同时允许出现变体或扩展。

分组使用保留名称 $root 作为令牌名来支持根令牌:

理由:使用 $root 作为保留令牌名可以消除组引用与令牌引用之间的歧义,同时保持清晰明了的语法。$ 前缀可防止与用户定义的令牌名称发生冲突,并与规范中其他保留属性保持一致。

6.3 分组属性

分组 MAY 可以包含以下属性:

属性 是否必需 说明
$description No 描述该分组用途的纯 JSON 字符串
$type No 作为分组内未明确声明类型的令牌的默认类型。类型继承适用于嵌套分组及其令牌,除非被覆盖
$extends No 从另一个分组继承令牌和属性。详见 分组扩展
$deprecated No 将该分组标记为已弃用。值可以是 truefalse 或字符串说明
$extensions No 厂商特定的扩展,工具 MAY 可以添加专有数据

6.3.1 $deprecated

分组 MAY 可以包含可选的 $deprecated 属性以将整个分组标记为已弃用。这会扩展到该分组内的所有子令牌,除非被显式覆盖。

说明
true 该分组已弃用(未提供说明)
string 该分组已弃用,且该字符串为说明
false 该分组未弃用(可用于覆盖父分组默认值)

6.3.2 $extensions

分组 MAY 可以包含可选的 $extensions 属性,工具 MAY 可以在其中添加专有的、用户、团队或厂商特定的数据。每个工具 MUST 必须使用带厂商标识的键,其值 MAY 可以是任意合法的 JSON 数据。

6.4 分组扩展

分组 MAY 可以包含可选的 $extends 属性,用于继承另一个分组的令牌和属性。$extends MUST NOT 不得引用令牌。$extends 属性是 JSON Schema 的 $ref 关键字的语法糖,并遵循 [json-schema-2020-12] 中定义的相同语义行为。

6.4.1 与 JSON Schema $ref 等价

$extends 属性在语义上等同于 JSON Schema 的 $ref 关键字(如 [json-schema-2020-12] 所述)及其后续版本。以下两个分组定义在功能上是相同的:

使用 $extends(设计令牌语法):

{
  "button-primary": {
    "$extends": "{button}",
    "background": {
      "$value": {
        "colorSpace": "srgb",
        "components": [0.8, 0, 0.4],
        "hex": "#cc0066"
      }
    },
    "focus": {
      "$value": {
        "colorSpace": "srgb",
        "components": [1, 0.2, 0.6],
        "hex": "#ff3399"
      }
    }
  }
}

使用 $ref(JSON Schema 语法):

{
  "button-primary": {
    "$ref": "#/button",
    "background": {
      "$value": {
        "colorSpace": "srgb",
        "components": [0.8, 0, 0.4],
        "hex": "#cc0066"
      }
    },
    "focus": {
      "$value": {
        "colorSpace": "srgb",
        "components": [1, 0.2, 0.6],
        "hex": "#ff3399"
      }
    }
  }
}

6.4.2 引用解析与评估

扩展解析遵循简单的处理流程:

  1. 查找目标:解析 $extends 引用以定位目标分组
  2. 复制继承内容:以目标分组的所有令牌和属性为起点
  3. 应用本地覆盖:在相同路径处用本地定义替换任何继承的令牌/属性
  4. 添加新内容:包含任何本地存在但继承组中不存在的令牌/属性

以上规则会创建一个已解析的新分组,按照覆盖规则合并继承和本地内容。

注意:实现

6.4.3 继承语义

分组扩展遵循 深度合并 行为,本地属性会在相同路径下覆盖继承属性:

  1. 继承:继承所引用分组的所有令牌和属性(不允许循环引用)
  2. 覆盖:本地令牌和属性替换具有相同路径的继承项
  3. 新增:具有新路径的本地令牌和属性与继承项并存

覆盖规则:

  • 相同路径 = 覆盖:如果继承分组和本地分组在相同路径定义了令牌,则以本地定义为准
  • 不同路径 = 合并:不同路径的令牌在最终结果中并存
  • 整体替换:在覆盖时,整个令牌定义会被替换(而不是逐属性合并)

input-amount 的结果:

令牌 最终值
field.width "100px"(本地覆盖生效)
field.background {"colorSpace": "srgb", "components": [1, 1, 1], "hex": "#ffffff"} (继承,自本地未覆盖)

多级覆盖示例:

extended 的结果:

令牌 最终值 来源
color "#red" 已覆盖
spacing "16px" 继承
border "1px solid" 新增

6.4.4 循环引用预防

分组 MUST NOT 不得创建循环继承链。以下模式是 无效的

有效的继承模式:

6.4.5 支持的引用格式

$extends 支持与 设计令牌别名 相同的引用格式。

6.4.6 错误条件

$extends 的错误处理遵循 JSON Schema $ref 的错误模式:

  • 无法解析的引用:找不到目标分组时
  • 无效的目标:引用指向的不是分组(例如指向一个令牌)时
  • 循环引用:扩展链产生循环时
  • 约束违规:本地属性违反继承约束时

工具 MUST 必须实现与 JSON Schema 验证器用于 $ref 解析相同的错误检测和报告模式。

6.4.7 实现指导

实现设计令牌解析的工具 MAY 可以选择:

  1. 转换为 $ref$extends 转换为标准 JSON Schema $ref 语法,并使用现有 JSON Schema 库进行验证
  2. 原生实现:直接实现 $extends,使用与 JSON Schema $ref 处理相同的算法
  3. 混合方法:在保持设计令牌特定引用语法的同时,使用 JSON Schema 库进行验证

无论采用何种实现方式,语义行为 MUST 必须与 JSON Schema 2020-12 或更高版本中指定的 $ref 等价。

6.4.8 与 JSON Schema 规范的关系

本规范将 $extends 定义为 JSON Schema 的 $ref 关键字的语法糖,提供了设计令牌特定的引用语法,同时保持等价行为。上述深度合并语义与 JSON Schema 2020-12 在处理带有同级属性的 $ref 时的行为一致。

对于熟悉 JSON Schema 的实现者,$extends 的行为等同于:

  • "$extends": "{group}" 转换为 "$ref": "#/group"
  • 应用 JSON Schema 2020-12 中对 $ref 的解析并评估同级属性

实现本规范的工具 MAY 可以选择:

  1. 转换方法:$extends 转换为 $ref 并使用 JSON Schema 库
  2. 直接实现:实现上文描述的深度合并行为
  3. 混合方法:在保持设计令牌语法的同时使用 JSON Schema 进行验证

无论采用何种实现方法,面向用户的行为 MUST 必须与本规范描述的深度合并语义相匹配。

6.5 空分组

分组 MAY 可以是空的(不包含令牌或嵌套分组)。尽管它们看起来没有立即用途,但它们:

注意:令牌与分组的歧义

6.6 引用与 JSON 指针集成

当前使用花括号 ({group.token}) 的 令牌引用语法 为保持向后兼容性和开发者可用性而保留。不过,工具 MAY 也可以支持 JSON Pointer 表示法以满足高级用例。

6.6.2 JSON 指针支持

工具 MUST 必须支持按 [rfc6901] 定义的 JSON Pointer 引用,使用 $ref 属性:

6.7 处理规则

6.7.1 令牌解析顺序

处理分组时,工具 MUST 必须遵循下列解析顺序:

  1. 本地令牌 - 具有 $value 属性的直接子项
  2. 根令牌 - 名为 $root 的令牌
  3. 继承令牌 - 通过 $extends 继承的令牌(若未被覆盖)
  4. 嵌套分组 - 递归处理

6.7.2 路径构建

令牌路径通过用句点 (.) 连接分组名和令牌名来构造。保留令牌名 $root 包含在路径中以保持引用的明确无歧义。

示例:

位置 路径 备注
/color/accent/$root color.accent.$root 令牌路径
/color/accent/light color.accent.light 令牌路径
/color/accent 对于令牌解析无效,但对于分组有效

6.7.3 类型继承

类型解析按以下优先级规则进行:

  1. 令牌显式的 $type 属性(最高优先级)
  2. 已解析分组的 $type 属性(在扩展解析之后)
  3. 父分组的 $type 属性(向上遍历层级)
  4. 若无法确定类型,则令牌无效

带扩展的类型解析: 由于 $extends 遵循 JSON Schema $ref 语义,类型继承行为由约束验证决定,而不是显式的合并规则。本地类型约束会与继承的约束一起根据 JSON Schema 的验证模式进行评估。

在此示例中,分组 extended 必须同时满足其本地的 $type: "dimension" 约束以及来自所引用 base 分组的任何适用约束,遵循 JSON Schema 的约束解析规则。

6.7.4 循环引用检测

工具 MUST 必须检测并对以下类型的循环引用抛出错误:

  • 令牌别名中的循环引用(见 引用
  • 分组扩展中的循环引用($extends 引用)
  • JSON Pointer 引用中的循环引用(若支持 $ref

对于 $extends 的循环引用检测遵循与 JSON Schema $ref 相同的要求。工具 SHOULD 应当实现与 JSON Schema 验证器相同的环检测算法。

工具 MUST 必须将此作为影响分组 abc 的错误进行报告。

6.8 迁移与兼容性

本规范设计为与现有设计令牌文件向后兼容。实现本规范的工具:

6.9 示例

6.9.1 含根令牌的基础分组

6.9.2 带覆盖的分组扩展示例

解析后的令牌:

  • {input-amount.field.width}{ "value": 100, "unit": "px" } (已覆盖)
  • {input-amount.field.background}#ffffff (从 input 继承)

这演示了组件扩展基础组件但覆盖特定令牌同时继承其他令牌的关键用例。

6.9.3 复杂层级结构

该结构创建的可访问令牌如下:

令牌引用 解析后值
{color.brand.$root} {"colorSpace": "srgb", "components": [0, 0.4, 0.8], "hex": "#0066cc"}
{color.brand.light} {"colorSpace": "srgb", "components": [0.2, 0.533, 0.867], "hex": "#3388dd"}
{color.semantic.success.$root} {"colorSpace": "srgb", "components": [0, 0.8, 0.4], "hex": "#00cc66"}
{color.semantic.error.dark} {"colorSpace": "srgb", "components": [0.6, 0, 0], "hex": "#990000"}

6.10 使用场景

6.10.1 文件编写与组织

分组允许令牌文件作者更好地组织其令牌文件。相关令牌可以嵌套到分组中以符合团队的命名约定或心智模型。在手动编写文件时,使用分组也比使用重复前缀的平铺令牌列表更简洁。

例如:

……相比下面这种平铺结构,可能更方便输入且更易阅读:

6.10.2 GUI 工具

允许用户通过 GUI 选择或编辑令牌的工具 MAY 可以使用分组结构以适当的方式呈现逐步披露(例如可折叠的树状视图)。

Figure 1 分组的逐步披露

6.10.3 转换工具

令牌名称在同一文件中不保证唯一。相同名称可以在不同分组中使用。此外,转换工具 MAY 可能需要以可唯一识别的方式导出设计令牌,例如在代码中作为变量。因此,转换工具 SHOULD 应当使用设计令牌的路径,因为路径在文件内是唯一的。

例如,像 转换工具(如 Style Dictionary)可能会使用如下的设计令牌文件:

……并通过拼接路径创建变量名,将其输出为 Sass 变量,如下所示:

7. 别名 / 引用

令牌可以引用另一个令牌的值,而不是直接拥有显式的值。换句话说,一个令牌可以是另一个令牌的别名。本规范将“alias(别名)”和“reference(引用)”视为同义词并交替使用。

别名的用途包括:

7.1 引用语法

设计令牌支持两种在令牌文件中引用内容的不同语法:

7.1.1 花括号语法(令牌引用)

花括号语法专用于引用完整的令牌值,并且总是解析为目标令牌的 $value 属性。

在此示例中,{colors.blue} 解析为完整的颜色对象 {"colorSpace": "srgb", "components": [0, 0.4, 0.8], "hex": "#0066cc"}

重要说明:花括号引用只能目标为完整令牌(具有 $value 属性的对象),不能用于访问令牌值内的单个属性或文档中的任意位置。

7.1.2 JSON Pointer 语法(必须支持)

对于需要访问令牌值内特定属性或文档结构其他部分的高级用例,令牌必须支持由 [rfc6901] 定义的 JSON Pointer 表示法,使用 $ref 属性。实现本规范的工具必须支持 JSON Pointer 语法。

在此示例中:

  • "$ref": "#/colors/blue/$value" 等价于 "{colors.blue}"
  • "$ref": "#/colors/blue/$value/components/0" 访问蓝色的红色分量(索引 0)

主要差异:

方面 花括号 {token} JSON Pointer $ref
目标 仅完整令牌 任意文档位置
隐式路径 始终附加 /$value 需要显式的完整路径
使用场景 令牌到令牌的引用 属性级别引用
语法 {group.token} #/group/token/$value

7.2 引用解析

当工具需要令牌的实际值时,必须对引用进行解析 —— 即查找被引用的令牌并获取其值。工具应当保留引用,只有在需要获取实际值时才解析它们。例如,在一个设计工具中,被别名引用的令牌的值发生改变时,应当在所有使用这些别名的地方反映出来。

7.2.1 解析算法

针对花括号引用:

  1. 解析引用:{group.token} 中提取令牌路径
  2. 拆分路径:转换为段数组 ["group", "token"]
  3. 定位令牌:查找目标令牌对象
  4. 验证令牌:确保目标具有 $value 属性
  5. 返回令牌值:提取并返回 $value 的内容
  6. 检查循环:维护解析引用的调用栈以检测循环

针对 JSON Pointer 引用:

  1. 解析 JSON Pointer:#/path/to/target 中提取路径段
  2. 遍历文档:逐段导航文档结构
  3. 应用 JSON Pointer 规则:
    • 数组上下文中的数字段被视为数组索引
    • 对象上下文中的所有段被视为属性名
    • 处理转义字符(~0, ~1
  4. 验证目标:确保最终目标存在且可访问
  5. 返回值:提取并返回解析出的值

7.2.2 链式引用

别名可以引用其他别名。在此情况下,工具必须沿着引用链逐一解析,直到找到具有显式值的令牌为止。

在此示例中,{semantic.link} 通过链式跟随解析:semantic.linksemantic.brandbase.primary,最终解析为与 {base.primary} 相同的颜色值。

7.2.3 循环引用

引用不得形成循环。如果设计令牌文件包含循环引用,则该循环链中所有令牌的值均为未知,工具应当向用户显示适当的错误或警告信息。

工具必须检测并将其报告为影响该循环链中所有令牌的错误。

7.3 属性级引用

JSON Pointer 语法允许引用复合令牌中特定的属性,而不仅限于整个令牌值。这使得可以细粒度地重用令牌组件,同时保持语义关系。

重要:属性级引用需要使用 JSON Pointer 语法($ref),不能使用花括号语法表示。

7.3.1 颜色分量引用

7.3.2 尺寸组件引用

在此示例中:

  • layout.small 使用与 base.spacing 相同的数值(16),但使用不同的单位(rem
  • layout.large 使用与 base.spacing 相同的单位(px),但数值不同(32)

7.3.3 排版组件引用

在此示例中:

  • 两个标题都继承了 base.textfontFamilylineHeight
  • 每个标题都定义了自己的 fontSizefontWeight
  • 对基础字体族或行高的更改会自动影响所有标题

7.4 JSON Pointer 路径构建与解析

JSON Pointer 语法提供对设计令牌文档结构中任何位置的直接访问,遵循 [rfc6901] 定义的标准 JSON Pointer 规则。

7.4.1 路径构建规则

  • 根引用: #/(指向文档根)
  • 对象属性: 使用 / 分隔每一级(例如 #/group/token/$value
  • 数组索引: 数组元素使用数字索引(例如 #/color/$value/components/0
  • 特殊字符: 必须根据 JSON Pointer 规则进行转义:
    • ~ 变为 ~0
    • / 变为 ~1

7.4.2 令牌值访问模式

由于设计令牌将其值存储在 $value 属性中,指向令牌值的 JSON Pointer 路径遵循可预测的模式:

JSON Pointer 等价的花括号引用 说明
#/colors/blue/$value {colors.blue} 完整的令牌值
#/colors/blue/$value/hex N/A 颜色的 hex 属性
#/colors/blue/$value/components/0 N/A 颜色的第一个分量
#/colors/blue/$type N/A 令牌类型元数据

7.4.3 JSON Pointer 的解析算法

  1. 解析 JSON Pointer:#/path/to/target 中提取路径段
  2. 遍历文档:逐段导航
  3. 应用 JSON Pointer 规则:
    • 数组上下文中的数字段转为数组索引
    • 对象上下文中的段视为属性名
    • 处理转义字符(~0, ~1
  4. 验证目标:确保最终目标存在且可访问
  5. 返回值:提取并返回解析出的值

7.4.4 花括号解析算法

  1. 解析引用:{group.token} 中提取令牌路径
  2. 拆分路径:转换为段数组 ["group", "token"]
  3. 定位令牌:查找目标令牌对象
  4. 验证令牌:确保目标具有 $value 属性
  5. 返回令牌值:提取并返回 $value 的内容
  6. 检查循环:维护解析引用的调用栈以检测循环

7.4.5 错误条件

工具必须对以下情况报告错误:

  • 语法无效:花括号或 JSON Pointer 语法格式错误
  • 路径不可解析:目标路径在文档中不存在
  • 无效的令牌引用:花括号语法引用了非令牌对象
  • 循环引用:引用链回到自身
  • 类型不匹配:被引用的值与期望类型不兼容

7.4.6 路径示例

令牌路径 JSON Pointer 花括号语法
根令牌 "primary" #/primary {primary}
嵌套令牌 #/colors/blue {colors.blue}
数组元素 #/color/components/0 不支持
属性含空格 #/brand colors/primary {brand colors.primary}
属性含斜杠 #/my~1group/token {my/group.token}

7.5 实现指导

7.5.1 面向工具开发者

实现设计令牌解析的工具必须

  1. 支持花括号语法,作为令牌到令牌引用的主要引用机制
  2. 支持 JSON Pointer 语法,用于文档级引用和属性访问
  3. 验证引用目标,确保其指向有效的令牌(对花括号)或有效的文档位置(对 JSON Pointer)
  4. 按照本规范定义的解析算法解析引用(参见 解析算法
  5. 在尝试解析之前检测循环引用
  6. 在内存/存储中保留引用,并仅在需要值时才解析
  7. 将被引用令牌的更改传播到所有别名

7.5.2 消歧示例

清晰解析:

引用 结果 备注
#/ambiguous/data/0 10 JSON Pointer 数组索引
{ambiguous.metadata.0} "Info about first item" 花括号对象属性
{ambiguous.data.0} 错误 花括号不能访问数组索引
{ambiguous.metadata.2} 错误 属性 "2" 不存在

7.5.3 错误条件

工具必须对以下情况报告错误:

  • 引用语法无效:花括号或 JSON Pointer 语法格式错误
  • 引用不可解析:目标路径不存在
  • 循环引用:引用链回到自身
  • 类型不匹配:被引用的属性类型与令牌类型不兼容
  • 无效的属性路径:尝试引用不存在的属性

7.6 与 JSON Schema 的关系

本规范中定义的引用语法在兼容 JSON Schema 模式的同时,也满足设计令牌编写的特定需求:

重要说明:尽管设计令牌中的 JSON Pointer 引用($ref)遵循与 JSON Schema 相同的语法,但花括号引用({token})是设计令牌特有的,具有不同的语义(自动解析 $value 并仅针对令牌),与标准 JSON Schema 引用不同。


本规范提供了一种灵活且基于标准的方法来处理令牌引用,在作者友好性与技术精确性之间取得平衡,既支持简单的令牌别名,也支持复杂的属性级关系。

8. 类型

许多工具需要知道给定令牌表示哪种类型的值,以便对其进行合理处理。转换工具 MAY(可能)需要根据类型对令牌进行不同的转换或格式化。设计工具 MAY(可能)在编辑特定类型的令牌时向用户提供不同类型的输入(例如颜色选择器、滑块、文本输入等)。样式指南生成器 MAY(可能)会为不同类型的令牌使用不同的预览方式。

本规范定义了一系列面向设计的类型,每个设计令牌 MUST(必须)使用这些类型之一。此外,该令牌的值 MUST(必须)遵循本规范为所选类型定义的规则和语法。

令牌的类型可以通过为其设置 $type 属性来直接指定。或者,它可以从其父分组之一继承类型,或作为具有所需类型的令牌的别名。

如果未为令牌设置显式类型,工具 MUST(必须)将该令牌视为无效,不得尝试从其值推断其他类型。

如果设置了显式类型,但值不符合预期语法,则该令牌无效,应向用户显示适当的错误信息(工具 SHOULD)。换言之,$type 属性声明了该令牌允许的值类型。(这类似于 Java 或 TypeScript 等编程语言中的类型系统,不兼容声明类型的值会导致编译错误。)

8.1 颜色

表示 UI 中的颜色。有关如何表示颜色的详细信息,请参阅 Color 模块。

8.2 尺寸(Dimension)

表示 UI 中单维度的距离量,例如位置、宽度、高度、半径或厚度。$type 属性 MUST(必须)设置为字符串 dimension。其值 MUST(必须)为一个对象,包含数值型的 value(整数或浮点数)和度量单位的 unit"px""rem")。

类型 是否必需 说明
value number 表示数值的整数或浮点值。
unit string 距离单位。支持值:"px", "rem"

例如:

8.2.1 验证

  • $value.unit 仅可为 "px""rem"
    • px:表示视口上的理想化像素。在 Android 上等价于 dp,在 iOS 上等价于 pt。因此,转换工具 SHOULD(应当)将其转换为这些或其他等效单位(如有需要)。
    • rem:表示系统默认字体大小的倍数(该默认大小 MAY 可由用户配置)。1rem 等于默认字体大小的 100%。在 Android 上 1rem 等价于 16sp。并非所有平台都有 rem 的等价物,因此转换工具 MAY(可能)需要在此类平台上通过假定一个默认字体大小(通常为 16px)将其有损转换为固定像素大小。
  • 即使 $value.value0,也必须提供 $value.unit

8.3 字体族(Font family)

如下所示的简单方法可能适合规范的第一阶段,但由于平台/操作系统/浏览器的限制,这个问题可能比看起来更复杂。

表示一个字体名称或按优先顺序排列的字体名称数组。$type 属性 MUST(必须)设置为字符串 fontFamily。其值 MUST(必须)要么是包含单个字体名称的字符串,要么是由多个字符串组成的数组,每个字符串均为单个字体名称。

例如:

8.4 字体粗细(Font weight)

表示字体粗细。$type 属性 MUST(必须)设置为字符串 fontWeight。其值必须是范围 [1, 1000] 内的数字,或下表中定义的预定义字符串别名之一。

较小的数字表示较轻的粗细,较大的数字表示更粗的字体,这符合 OpenType 的 wght 规范。预定义的字符串值是对应特定数值的别名。例如 100"thin""hairline" 都表示相同的值。

数值 字符串别名
100 thin, hairline
200 extra-light, ultra-light
300 light
400 normal, regular, book
500 medium
600 semi-bold, demi-bold
700 bold
800 extra-bold, ultra-bold
900 black, heavy
950 extra-black, ultra-black

超出 [1, 1000] 范围的数值以及任何其他字符串值(包括仅大小写不同的字符串)都是无效的,工具 MUST(必须)拒绝这些值。

示例:

8.5 时长(Duration)

表示动画或动画周期完成所需的时间长度(以毫秒为单位),例如 200 毫秒。$type 属性 MUST(必须)设置为字符串 duration。其值 MUST(必须)为一个对象,包含数值型的 value(整数或浮点数)和时间单位的 unit"ms""s")。毫秒是时间单位,等于一秒的千分之一。

类型 是否必需 说明
value number 表示数值的整数或浮点值。
unit string 时间单位。支持值:"ms"(毫秒)、"s"(秒)。

例如:

8.5.1 验证

  • $value.unit 仅可为 "ms""s"

8.6 三次贝塞尔(Cubic Bézier)

表示动画属性在动画持续时间内值如何向完成状态演进,产生诸如加速、减速或弹跳等视觉效果。$type 属性 MUST(必须)设置为字符串 cubicBezier。其值 MUST(必须)为包含四个数字的数组。这四个数字表示两个控制点(P1、P2),每个点包含一个 x 坐标和一个 y 坐标:[P1x, P1y, P2x, P2y]。P1 和 P2 的 y 坐标可以是任意实数(范围 [-∞, ∞]),但 x 坐标被限制在 [0, 1] 范围内。

例如:

8.7 数字(Number)

表示一个数字。数字可以为正、负并带小数。数字型令牌的示例用途包括 渐变停止位置 或无单位的行高。$type 属性 MUST(必须)设置为字符串 number。其值 MUST(必须)为一个 JSON 数字值。

8.8 补充类型

本节为非规范性内容。

尚待在此处记录的类型可能包括:

9. 复合类型

前几章定义的类型(如 color 和 dimension)都具有单一值。例如,一个颜色令牌的值是 一个 颜色。然而,UI 设计中还有一些方面是由多个值组合而成的。例如,阴影样式就是由颜色、X 与 Y 偏移、模糊半径和扩散半径等组合而成。

每个阴影样式都有完全相同的组成部分(颜色、X 与 Y 偏移等),但各自的值会不同。此外,每个部分的值(也称为“子值”)始终属于相同的类型。阴影的颜色必须始终是 color 值,X 偏移必须始终是 dimension 值,依此类推。因此,阴影样式是遵循预定义结构的值的组合。换言之,阴影样式本身是一种类型。这类类型称为 复合类型

具体来说,复合类型具有以下特征:

9.1 复合类型中的数组别名

当复合类型包含数组属性时,数组中的每个元素可以是显式值,也可以是对适当类型令牌的引用。数组中的引用解析为单一值,并不会导致数组展开或扁平化。这允许在某些数组元素为引用而其他为显式值时实现灵活的组合。

数组别名遵循以下原则:

  1. 单值解析:数组中的引用始终解析为适当类型的单一值,绝不解析为数组本身。
  2. 不进行扁平化:当引用一个数组时,被引用的整个数组作为引用数组中的单个元素来处理。
  3. 类型安全:每个数组元素(显式或引用)必须符合该复合类型期望的子值类型。
  4. 混合组合:数组可以自由混合显式值与引用。

例如,具有数组值的阴影令牌可以将对其他阴影令牌的引用与显式阴影对象混合:

{
  "layered-shadow": {
    "$type": "shadow",
    "$value": [
      "{base.shadow}",
      {
        "color": "{brand.accent}",
        "offsetX": { "value": 4, "unit": "px" },
        "offsetY": { "value": 4, "unit": "px" },
        "blur": { "value": 8, "unit": "px" },
        "spread": { "value": 0, "unit": "px" }
      }
    ]
  }
}

若某个设计令牌的类型恰好是复合类型,则有时也称其为复合(设计)令牌。除了类型之外,复合令牌没有其他特殊之处。它们可以具有诸如 $description$extensions 之类的附加属性。它们也可以被其他设计令牌引用。

9.2 分组与复合令牌的区别

乍一看,分组和复合令牌可能看起来非常相似。然而,它们旨在解决不同的问题,因此存在一些重要差异:

9.3 描边样式(Stroke style)

表示应用于线条或边框的样式。$type 属性 MUST 必须设置为字符串 strokeStyle。其值 MUST 必须是下列之一:

Issue 98: Stroke style type feedback Composite Type Feedback
当前关于描边样式的规范是否适用?是否需要更多的子值(例如等同于 SVG 的 stroke-linejoinstroke-miterlimitstroke-dashoffset 属性)?

9.3.1 字符串值

字符串形式的描边样式值 MUST 必须设置为下列预定义值之一:

  • solid
  • dashed
  • dotted
  • double
  • groove
  • ridge
  • outset
  • inset

这些值与 CSS 中等价的 “line style” 值 含义相同。根据 CSS 规范,它们的确切渲染是实现相关的。例如,dashed 样式中虚线与空白的长度在不同工具之间可能有所差异。

9.3.2 对象值

对象形式的描边样式值 MUST 必须包含以下属性:

  • dashArray:一个由 dimension 值 和/或对 dimension 令牌的引用组成的数组,用以指定交替虚线与间隙的长度。数组中的每个元素必须是显式的 dimension 值或对 dimension 令牌的引用。如果提供的是奇数个值,则会重复该值列表以得到偶数个值。
  • lineCap:下列预定义字符串值之一:"round""butt""square"。这些值与 SVG 中 stroke-linecap 属性的含义相同。

9.3.3 回退(Fallbacks)

字符串值和对象值是表达描边样式的两种互斥方式。例如,一些字符串值(如 insetgroove)无法仅通过 dashArraylineCap 来表达,因为它们需要实现相关的方式对边框或轮廓的某些部分进行加亮或变暗。反之,精确定义的 dashArraylineCap 子值组合未必能产生与 dasheddotted 关键字相同的视觉效果,因为这些也依赖于实现细节。

此外,某些工具与平台可能不支持本类型表示的全部描边样式。当在显示或导出不被其原生支持的 strokeStyle 令牌时,它们应回退到其支持的最接近近似效果。

如何选择“最接近的近似”属于实现细节。不过,下列示例说明工具在某些场景中MAY(可以)使用的回退方案。

9.4 边框(Border)

表示边框样式。$type 属性 MUST 必须设置为字符串 border。其值 MUST 必须是一个具有下列属性的对象:

Issue 99: Border type feedback Composite Type Feedback
当前关于边框的规范是否适用?是否需要更多子值以考虑诸如 outset、border images、多重边框等某些平台与设计工具所具备的特性?

9.5 过渡(Transition)

表示两个状态之间的动画过渡。$type 属性 MUST 必须设置为字符串 transition。其值 MUST 必须是一个对象,包含下列属性:

Issue 103: Transition type feedback Composite Type Feedback
当前关于过渡的规范是否适用?考虑到这些参数本身并不能指定 UI 的哪个方面被过渡以及起止状态,单独作为过渡参数是否仍然有用?

9.6 阴影(Shadow)

表示阴影样式。$type 属性 MUST 必须设置为字符串 shadow。其值 MUST 必须是下列之一:

当值为数组时,每个元素必须是显式的阴影对象或对另一个阴影令牌的引用。数组中的引用解析为单一的阴影对象,并不会导致数组扁平化。

每个阴影对象(无论是显式的还是被引用的)MUST 必须具有下列属性:

Issue 100: Shadow type feedback Composite Type Feedback
当前关于阴影的规范是否适用?是否需要支持多个阴影(如某些工具和平台所做的)?

9.7 渐变(Gradient)

表示颜色渐变。$type 属性 MUST 必须设置为字符串 gradient。其值 MUST 必须是由渐变停止对象和/或对渐变令牌的引用组成的数组。数组中的每个元素必须是显式的渐变停止对象或对渐变令牌的引用。引用解析为单一的渐变对象,并不导致数组扁平化。

每个渐变停止对象(无论是显式的还是被引用的)MUST 必须具有以下结构:

如果在渐变轴的起点或终点没有明确的停止(即没有 position 为 0 或 1 的停止),则应将最靠近各端的停止颜色扩展到该端点。

Issue 101: Gradient type feedback Color Type Enhancements
当前关于渐变的规范是否适用?是否需要同时指定渐变类型(例如 linear、radial、conical 等)?

9.8 排版(Typography)

表示一种排版样式。$type 属性 MUST 必须设置为字符串 typography。其值 MUST 必须是一个对象,包含下列属性:

A. 问题摘要

B. 参考文献

B.1 规范性参考文献

[json-schema-2020-12]
JSON Schema: A Media Type for Describing JSON Documents. Draft 2020-12. Austin Wright; Henry Andrews; Ben Hutton; Greg Dennis. Internet Engineering Task Force (IETF). 10 June 2022. Internet-Draft. URL: https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-01
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[rfc6901]
JavaScript Object Notation (JSON) Pointer. P. Bryan, Ed.; K. Zyp; M. Nottingham, Ed. IETF. April 2013. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc6901
[RFC8174]
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba. IETF. May 2017. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
[RFC8259]
The JavaScript Object Notation (JSON) Data Interchange Format. T. Bray, Ed. IETF. December 2017. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc8259