第3章 数据结构:颜色、字型、间距、形状等命名规范与嵌套规则,可扩展性设计

3.1 原理概述

Material 3 主题云分发的核心是 Design 的标准化数据结构。 是主题属性的最小原子单元,每一枚 包含一个语义化名称和一个关联值。在云端分发场景下, 结构必须同时满足三项目标:

  • 命名自解释:开发者读取 名即可理解其用途,无需翻阅文档。
  • 嵌套可推导:通过层级关系自动推导变体(如浅色/深色、交互状态、密度缩放)。
  • 扩展易附加:在不破坏现有结构的前提下,允许品牌自定义新 或覆盖默认值。

本章将逐一拆解颜色、字型、间距、形状的命名规范、嵌套规则及可扩展性设计模式。

3.2 命名规范

命名采用 语义化 + 层级分隔符(点号或中线) 范式。推荐使用小写字母,单词间以中线连接,层级间以点号分隔。状态后缀统一附加在末端。

类别命名模式示例
颜色color.类别.角色.变体.状态color.primary.default.base、color.primary.default.hovered
字型type.尺寸族.层级.变体type.display.large.regular、type.body.medium.bold
间距spacing.方向.等级spacing.inline.sm、spacing.inset.lg
形状shape.元素.圆角等级shape.card.md、shape.button.full

3.2.1 颜色命名细则

颜色 结构固定为四段:color.{角色}.{变体}.{状态}。角色包括 primary、secondary、tertiary、error、surface、outline 等。变体为 default、container、on- 前缀派生。状态可选 base、hovered、focused、pressed、disabled。

✅ 正确命名示例:
color.primary.default.base        → #6750A4
color.primary.default.hovered     → #7C67B1
color.primary.container.base      → #EADDFF
color.surface.default.base        → #FFFBFE
color.error.default.hovered       → #B3261E

3.2.2 字型命名细则

字型 结构:type.{尺寸族}.{层级}.{字重}。尺寸族指 display、headline、title、body、label。层级用 large、medium、small 描述相对大小。字重值域固定为 regular、medium、bold。

type.display.large.regular         → font-size: 57px, line-height: 64px, weight: 400
type.headline.medium.bold          → font-size: 28px, line-height: 36px, weight: 700
type.body.small.regular            → font-size: 12px, line-height: 16px, weight: 400

3.3 嵌套规则

嵌套规则决定了 如何从通用到特殊层层覆盖。整个主题本身为一个嵌套对象,根节点下按类别分支,每个分支内再按角色、变体、状态逐级嵌套。

  • 类别嵌套:color、type、spacing、shape 属于顶层键。
  • 状态嵌套:状态(hovered/focused/pressed)必须位于变体之下,而非同级。
  • 变体嵌套:如 primary 下同时存在 default 和 container,它们共享 primary 的语义命名空间。

解析时采用 最长匹配优先 规则:读取完整 名后,按点号逐层查找,若当前层级缺失则向上回溯至最近父节点取得默认值(适用于未显式声明状态的场景)。

3.3.1 嵌套覆盖示例

// 基础主题
{
  "color": {
    "primary": {
      "default": {
        "base": "#6750A4",
        "hovered": "#7C67B1"
      },
      "container": {
        "base": "#EADDFF"
      }
    }
  }
}

// 用户覆盖只指定 hovered 状态
{
  "color": {
    "primary": {
      "default": {
        "hovered": "#5A3E8A"    // 仅覆盖 hovered,base 仍从上方继承
      }
    }
  }
}

3.4 可扩展性设计

要实现云端与本地主题的无缝扩展,必须引入 别名引用 和 overlay 机制:

  1. 别名引用:允许 直接引用另一 的路径。解析器将所有别名展开为最终值,避免重复赋值。
  2. 覆盖层(Overlay):云分发时每次合并仅 diff,用户只需提供被修改的 ,未修改部分自动从基线继承。
  3. 自定义 命名空间:品牌方可在任意类别下添加 custom. 前缀的 ,系统保证不与官方 冲突。
💡 扩展实践: 第三方主题包应遵循 vendor.品牌名.类别.角色... 模式。例如 vendor.acme.color.brand.light,云服务端通过白名单允许访问。

3.5 数据结构完整实现示例(JSON)

以下是一个符合 Material 3 规范的 主题片段,展示了颜色、字型、间距、形状的完整嵌套结构:

{
  "$schema": "https://m3.themes.io/-v1.json",
  "version": "1.0.0",
  "extensible": true,
  "color": {
    "primary": {
      "default": { "base": "#6750A4", "hovered": "#7C67B1", "focused": "#A28FC9", "pressed": "#4F378B" },
      "container": { "base": "#EADDFF", "hovered": "#DEC8FA", "focused": "#C9B0E6", "pressed": "#A88AD4" }
    },
    "secondary": {
      "default": { "base": "#625B71", "hovered": "#757283", "focused": "#9A97A8", "pressed": "#4A4458" },
      "container": { "base": "#E8DEF8", "hovered": "#D7C8F0", "focused": "#C4B0E0", "pressed": "#A792C8" }
    },
    "surface": {
      "default": { "base": "#FFFBFE", "hovered": "#F5F0F6" },
      "container": { "base": "#F7F2FA" }
    }
  },
  "type": {
    "display": { "large": { "regular": "3.5625rem/4rem 400", "bold": "3.5625rem/4rem 700" } },
    "headline": { "large": { "regular": "2rem/2.5rem 400" } },
    "body": { "large": { "regular": "1rem/1.5rem 400" } },
    "label": { "large": { "regular": "0.875rem/1.25rem 500" } }
  },
  "spacing": {
    "inline": { "xs": "4px", "sm": "8px", "md": "16px", "lg": "24px" },
    "inset": { "xs": "4px", "sm": "8px", "md": "16px" },
    "stack": { "xs": "2px", "sm": "4px", "md": "8px", "lg": "12px" }
  },
  "shape": {
    "card": { "sm": "4px", "md": "8px", "lg": "16px" },
    "button": { "full": "50%" },
    "input": { "default": "4px" }
  },
  "_aliases": {
    "color.primary.default.hovered": "color.primary.default.hovered",
    "type.body": "type.body.large.regular"
  }
}

3.6 调试与验证

数据结构在云分发前必须通过以下检查:

检查项工具/方法典型命令
命名合规 Lint CLIm3--lint --schema v1 theme.json
别名完整性引用解析器m3-resolve-aliases theme.json --output resolved.json
嵌套深度JSON 深度检测jq '[paths(scalars)] | length' theme.json
覆盖层冲突Diff 合并器m3-overlay-merge base.json overlay.json --detect-conflict

3.7 常见错误

⚠️ 高频错误清单:
  • 命名歧义:使用 color.primary.dark 而非 color.primary.dark.hovered,导致状态层级丢失。
  • 覆盖丢失:仅提供部分变体时忘记声明 base,解析器向上回溯后取到错误的全局默认值。
  • 嵌套循环:别名 A 引用 B,B 又引用 A,造成无限递归(应使用 DAG 检测器预校验)。
  • 层级过深:超过 5 层嵌套(如 color.primary.default.container.hovered.pressed)会显著降低解析速度,建议控制在 4 层以内。

3.8 性能与稳定性优化

  • 扁平化缓存:生产环境将嵌套 展开为扁平 key-value 结构(如 color.primary.default.base → #6750A4),省去运行时递归解析。
  • 引用预编译:构建阶段将所有别名替换为实际值,用户侧仅存储最终值,避免拉取时进行多次网络请求。
  • 按需加载:云端按类别分片存储 (如 color.json、type.json),客户端按需拉取,减少初始载荷。
  • 版本哈希:在 包顶层添加 content_hash 字段,CDN 根据 hash 做增量更新,降低全量刷新频率。

3.9 数据结构的层级关系

数据结构层级关系图 Material3 Color Type Spacing Shape primary secondary surface display headline body inline inset card button 嵌套与扩展规则说明 • 每个类别节点下可嵌套角色(如 primary)、变体(default)、状态(hovered),深度 ≤4。 • 别名引用通过“_aliases”键实现,解析时展开为实际路径,不增加嵌套层数。 • 自定义 统一加前缀“custom.”,云服务端通过白名单隔离不同品牌方的扩展。