第1章 Material 3 主题系统概述:设计令牌架构、颜色源与角色、动态颜色机制
1.1 设计令牌架构(Design Architecture)
Material 3 的主题系统基于设计令牌(Tokens)构建。令牌是单一职责的命名变量,承载颜色、间距、圆角、阴影等原子化设计值,并通过层级结构实现从定义到组件的精确映射。
令牌分为三个层级:
- 系统令牌(System Tokens):最低层级的原始值,例如
sys.color.primary、sys.size.small。由设计系统直接定义,不可被组件覆盖。 - 别名令牌(Alias Tokens):对系统令牌的语义化引用,例如
color.on-primary映射到sys.color.on-primary,用于表达主题角色。 - 组件令牌(Component Tokens):绑定到具体 UI 组件的局部变量,例如
md.comp.filled-button.container-color。组件令牌只能引用别名令牌,不可直接引用系统令牌。
这种分层结构保证了全局统一性与局部灵活性:修改系统令牌可批量更新所有依赖它的组件,而组件令牌又允许特定组件微调外观。
📌 工程要点
令牌应使用连字符命名,避免空格或驼峰。在代码库中优先使用 JSON/YAML 集中管理令牌文件,例如
令牌应使用连字符命名,避免空格或驼峰。在代码库中优先使用 JSON/YAML 集中管理令牌文件,例如
tokens.json。Material 3 官方提供了 @material/tokens-v0-1 包作为基础令牌集。
1.2 颜色源与角色(Color Source & Roles)
Material 3 的颜色系统以种子颜色(Seed Color)为起点,通过算法生成完整的调色板(Palette),再将调色板中的色值映射到颜色角色(Color Roles)上。下表列出核心颜色角色及其语义用途:
| 颜色角色 | 典型用途 | 明暗主题对应 |
|---|---|---|
| Primary | 主要品牌色,用于关键组件(按钮、顶部栏) | 浅-深蓝色 / 深-亮蓝色 |
| On Primary | Primary 背景上的内容色(文字、图标) | 白色 / 黑色 |
| Secondary | 次要品牌色,用于浮动按钮、选择控件 | 浅-深紫色 / 深-亮紫色 |
| On Secondary | Secondary 背景上的内容色 | 白色 / 黑色 |
| Tertiary | 强调色,用于次要操作(链接、标签) | 暖色系(橙/黄) |
| Error | 错误状态色 | 红色系 |
| Background | 应用背景色 | 浅灰 / 深灰 |
| On Background | 背景上的内容色 | 黑色 / 白色 |
| Surface | 卡片、对话框的表面色 | 浅色 / 深色 |
| Surface Variant | 次要表面色(分割线、输入框填充) | 浅灰2 / 深灰2 |
| Outline | 边框、分隔线 | 中灰色 |
颜色角色在代码中通过别名令牌引用,例如 color.primary 对应 sys.color.primary。主题配置示例(JSON 格式):
{
"seed": "#6750A4",
"schemes": {
"light": {
"primary": "#6750A4",
"on-primary": "#FFFFFF",
"secondary": "#625B71",
"tertiary": "#7D5260",
"error": "#B3261E",
"background": "#FFFBFE",
"surface": "#FFFBFE",
"outline": "#79747E"
},
"dark": {
"primary": "#D0BCFF",
"on-primary": "#381E72",
"secondary": "#CCC2DC",
"tertiary": "#EFB8C8",
"error": "#F2B8B5",
"background": "#1C1B1F",
"surface": "#1C1B1F",
"outline": "#938F99"
}
}
}
1.3 动态颜色机制(Dynamic Color)
动态颜色是 Material 3 的关键差异化特性:应用自动从用户当前壁纸(Wallpaper)中提取主色调,生成一整套适配明暗主题的调色板,无需开发者手动配置。
其原理涉及三个步骤:
- 颜色提取:从壁纸中采样像素,通过 K-Means 聚类算法识别出最显著的色相作为种子颜色。
- 调色板生成:基于种子颜色,使用 HCT(Hue-Chroma-Tone)色彩空间计算调色板(共 13 个色值,包含 Primary、Secondary、Tertiary、Neutral 等变体)。
- 角色映射:将调色板中的色值按照固定规则分配到前述颜色角色中,形成
light和dark两套方案。
💡 平台差异注意
动态颜色仅原生支持 Android 12+(API 31)。在 Web / Flutter 环境中,需要手动从
动态颜色仅原生支持 Android 12+(API 31)。在 Web / Flutter 环境中,需要手动从
@material/material-color-utilities 库中调用 HCT 工具类实现类似功能。跨平台框架(如 React Native)通常需额外桥接。
以下是一个动态颜色的完整工作流程图:
1.4 常见错误与调试
- 颜色角色缺失:动态颜色自动生成时,若种子颜色过于单一(如纯黑),可能导致某些角色(如 Tertiary)无有效值。此时应检查
Chroma值是否低于 10—显式提供一个后备种子色。 - 对比度不足:动态生成的 on-primary 色可能与 primary 背景对比度低于 WCAG AA 标准。Material 3 的 HCT 引擎已内置对比度调节,但需确认 `Content`(内容色)变体是否正确启用。
- 令牌覆盖冲突:在组件级覆盖别名令牌时,不要直接写死十六进制值(如
#000),应通过ref(sys.color.primary)保持主题响应能力。
调试时可以使用 Material 3 官方 Theme Builder 工具(m3.material.io/theme-builder)导入种子色,观察所有角色色值及对比度验证报告。