Angular Material 3 Token 体系解析:m3 包结构与--mat-sys系统变量机制
【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components
导读
本文围绕 src/material/core/tokens/m3/README.md 所定义的 Material Design 3(MD3)token 定义包展开:该包从上游 [@material/tokens] 分叉而来,锁定v0_161版本的 token 定义,是 Angular Material 主题系统中 M3 组件样式与系统级 CSS 变量的数据源头。读完本文,你将理解 m3 包的目录/文件结构、六大 token 维度(颜色、字体排印、高度、形状、状态、动效)的取值定义方式,以及这些定义如何被_system.scss、_m3-tokens.scss等上层文件消费,最终转化为运行时可见的--mat-sys-*CSS 变量与组件私有 token。
包定位:从上游分叉的 MD3 token 定义
README.md给出了该包的核心定位:它是 Material Design 3 系统 token 的定义集合,与 Angular Material 主题实现中依赖的上游规范包进行了一次明确的分叉(fork)。分叉时间是 2024 年 7 月 22 日,此后仓库直接携带并使用v0_161版本的 token 值,而不是在构建时动态拉取 npm 上的@material/tokens。
README 同时记录了两条与上游的差异:
- 裁剪未使用 token:凡 Angular Material 当前未使用到的 token 都被移入
unused目录(在本仓库 m3 目录内体现为仅保留实际被消费的定义文件,未使用的定义不参与sass_library构建)。 - 统一格式化:token 文件的书写格式被调整为符合本仓库 stylelint 与 sass lint 规则,例如所有注释头统一为
Design system display name: Material 3与Design system version: v0.161(见 _md-sys-typescale.scss)。
从构建角度看,BUILD.bazel 将整个 m3 目录声明为一个名为m3的sass_library,其 srcs 包含_index.scss、六个_md-sys-*.scss、两个*-internal.scss以及_theme.scss共 10 个文件,任何上层 Sass 文件只需@use './m3'(如 _m3-tokens.scss)即可获得全部 token 函数。
模块入口:_index.scss 与导出面
_index.scss 是该包的统一入口,使用@forward将六个维度文件与_theme.scss全部导出:
@forward './md-sys-color'; @forward './md-sys-elevation'; @forward './md-sys-motion'; @forward './md-sys-shape'; @forward './md-sys-state'; @forward './md-sys-typescale'; @forward './theme';每个被 forward 的文件都暴露一个md-sys-xxx-values(...)纯函数,返回一个 Sass map。函数命名遵循统一约定:md-sys-color-values-light()/md-sys-color-values-dark()、md-sys-typescale-values()、md-sys-elevation-values()、md-sys-shape-values()、md-sys-state-values()、md-sys-motion-values()。上层代码统一通过m3.函数名(...)方式调用,例如 _m3-tokens.scss 中的m3.md-sys-color-values-dark($palettes)与m3.md-sys-color-values-light($palettes)。
系统 token 的六大维度与完整取值
以下逐一说明各维度函数的完整取值,全部以当前仓库源码为准(版本 v0.161)。
1. 颜色系统(md-sys-color)
_md-sys-color.scss 提供md-sys-color-values-light($palettes)与md-sys-color-values-dark($palettes)两个函数,分别面向浅色与深色主题。它们接收一个包含neutral、neutral-variant、primary、secondary、tertiary、error等色阶调色板(palette)的 map,然后从调色板的指定色阶(如primary, 40表示 primary 调色板第 40 阶)取出颜色值,组装成系统颜色 token map。
light 模式下的关键映射包括:
| Token | 取值来源 |
|---|---|
primary/on-primary | primary调色板 40 / 100 阶 |
primary-container/on-primary-container | primary调色板 90 / 30 阶 |
secondary/tertiary/error | 各自调色板 40 阶 |
surface/surface-container | neutral98 / 94 阶 |
surface-container-lowest/surface-container-highest | neutral100 / 90 阶 |
background/on-background | neutral98 / 10 阶 |
on-surface/on-surface-variant | neutral10 /neutral-variant30 阶 |
outline/outline-variant | neutral-variant50 / 80 阶 |
scrim/shadow | neutral0 阶 |
surface-tint | primary40 阶 |
dark 模式整体将色阶向暗部偏移,例如primary取 80 阶、primary-container取 30 阶、surface取neutral6 阶、surface-container取 12 阶,on-*类 token 相应取高亮度色阶(如on-primary为 20 阶)。
两个函数在组装完基础 map 后,都会与md-sys-color-internal中的内部取值合并(见 _md-sys-color-internal.scss)。该文件专门用于存放“与外部 Material Design 规范有分歧的内部专用值”,当前实现中values-light与values-dark均返回空 map(),即暂无内部差异;这一“预留扩展点”的设计意味着未来若组件需要偏离规范的自定义颜色,可以在此处增量补充,而不必改动主 map。
2. 字体排印系统(md-sys-typescale)
_md-sys-typescale.scss 的md-sys-typescale-values($typography)接收$typographymap,其中约定plain、brand、bold、medium、regular五个键,分别表示正文字体族、品牌字体族以及三种字重:
$plain: map.get($typography, plain); $brand: map.get($typography, brand); $bold: map.get($typography, bold); $medium: map.get($typography, medium); $regular: map.get($typography, regular);函数输出覆盖 Material 3 全部 15 种文字样式(display-large/medium/small、headline-large/medium/small、title-large/medium/small、body-large/medium/small、label-large/medium/small),每种样式都展开为 6 个 token:简写组合值(如body-large: $regular 1rem / 1.5rem $plain)以及-font、-line-height、-size、-tracking、-weight五个分项。典型取值如下:
display-large:3.562rem 字号、4rem 行高、-0.016rem字距、brand字体族、regular字重headline-medium:1.75rem 字号、2.25rem 行高、brand字体族title-large:1.375rem 字号、1.75rem 行高、brand字体族body-large:1rem 字号、1.5rem 行高、plain字体族label-large:0.875rem 字号、1.25rem 行高、medium字重,并额外提供label-large-weight-prominent: $boldlabel-medium/label-small:0.75rem / 0.688rem 字号,均带-weight-prominent变体
display、headline、title系列使用brand字体族,body、label系列使用plain字体族,这正是 M3 区分“品牌展示型文字”与“功能型正文”的设计原则。函数末尾同样与md-sys-typescale-internal合并(见 _md-sys-typescale-internal.scss),提供内部专用字体的扩展点。
3. 高度系统(md-sys-elevation)
_md-sys-elevation.scss 仅定义一个函数,返回 6 个高度等级的“高度值”(阴影扩散半径基准):
@function md-sys-elevation-values() { @return ( level0: 0, level1: 1, level2: 3, level3: 6, level4: 8, level5: 12 ); }注意这里存储的是阴影等级数值而非最终 box-shadow。真正将等级转换为 CSS 阴影的是上层 _system.scss 的system-level-elevationmixin:它以调色板neutral0 阶作为阴影颜色,调用elevation.get-box-shadow($level, $shadow-color)生成实际阴影,再以--mat-sys-levelN形式输出。这解释了_m3-tokens.scss中“elevation 需要归入 color 维度一起生成”的注释——阴影值必须与颜色值组合才有意义。
4. 形状系统(md-sys-shape)
_md-sys-shape.scss 定义 M3 的全部圆角尺寸 token:
@function md-sys-shape-values() { @return ( corner-none: 0, corner-extra-small: 4px, corner-extra-small-top: (4px 4px 0 0), corner-small: 8px, corner-medium: 12px, corner-large: 16px, corner-large-top: (16px 16px 0 0), corner-large-start: (16px 0 0 16px), corner-large-end: (0 16px 16px 0), corner-extra-large: 28px, corner-extra-large-top: (28px 28px 0 0), corner-full: 9999px ); }corner-full(9999px)用于实现完全圆角(胶囊/圆形元素);带-top、-start、-end后缀的变体是四值圆角列表,用于仅对特定角落生效的场景,例如顶部圆角(16px 16px 0 0)。
5. 状态层系统(md-sys-state)
_md-sys-state.scss 定义交互状态层(state layer)的透明度:
@function md-sys-state-values($exclude-hardcoded-values: false) { @return ( dragged-state-layer-opacity: 0.16, focus-state-layer-opacity: 0.12, hover-state-layer-opacity: 0.08, pressed-state-layer-opacity: 0.12 ); }这些透明度配合颜色 token 生成带透明度的状态层颜色,如 hover 8%、focus/pressed 12%、拖拽 16%。由于状态值经常与颜色值一起组合成 rgba 颜色,_m3-tokens.scss 的注释说明 state 因此被归入 color 维度一起生成,属于实现层面的刻意安排。
6. 动效系统(md-sys-motion)
_md-sys-motion.scss 定义 M3 的时长与缓动曲线 token,包含 16 个时长 token(duration-short150ms 至duration-extra-long41000ms)与 10 个缓动 token:
- 时长按档次递增:short(50/100/150/200ms)、medium(250/300/350/400ms)、long(450/500/550/600ms)、extra-long(700/800/900/1000ms)
- 缓动提供多套曲线:
standard、emphasized(二者均为cubic-bezier(0.2, 0, 0, 1))、legacy(cubic-bezier(0.4, 0, 0.2, 1))、linear,且standard、emphasized、legacy三族各有-accelerate/-decelerate变体
_theme.scss:系统变量 map 的组装
_theme.scss 是 m3 包的“收口”文件。其核心函数_create-system-app-vars-map($map)将任意 token map 的键转换为--mat-sys-<key>形式的 CSS 变量字符串:
@function _create-system-app-vars-map($map) { $new-map: (); @each $key, $value in $map { $new-map: map.set($new-map, $key, --mat-sys-#{$key}); } @return $new-map; }随后$_sys-maps汇总 color(light 模式)、typescale、elevation、state、shape 五个维度,并额外补两个非标准 token:
neutral10:用于表单原生 select 选项文字颜色neutral-variant20:用于 Sidenav 打开时的 scrim(容器背景阴影)
这些 map 全部 merge 进$_system(并附density-scale: 0),最终导出:
$sys-theme: (_mat-system: $_system);_mat-system这一键名正是上层代码读取系统 token 的入口——_m3-utils.scss 的get-system($theme)直接map.get($theme, _mat-system),而 _system.scss 则据此批量输出--mat-sys-*CSS 变量。值得注意的是:这里的$sys-theme提供的是变量引用(--mat-sys-key字符串),而真正把变量值落地的过程发生在 _system.scss 的各system-level-*mixin 中。
上层消费链路:从 token map 到 CSS 变量
m3 包本身不输出任何 CSS,它只是定义与函数的“数据层”。将其接入主题系统的是 _m3-tokens.scss 与 _system.scss。
_m3-tokens.scss:命名空间化 token 生成
generate-tokens($systems, ...)将六大系统 map 合并后输出命名空间化的 token map,其中(mat, theme)指向md-sys-color、(mat, typography)指向md-sys-typescale,让使用者通过组件 API 即可访问系统颜色与字体。三个更具体的入口函数:
generate-color-tokens($type, $palettes, $system-variables-prefix):根据light/dark选择浅色或深色系统颜色,并把 elevation、state(以及部分调色板值neutral-10、neutral-variant20)一并并入 color 维度输出generate-typography-tokens($typography, $system-variables-prefix):只输出 typescale 维度generate-base-tokens():输出 motion 与 shape 两个“与颜色、字体、密度无关”的维度
当启用系统变量时(sass-utils.$use-system-color-variables/$use-system-typography-variables),get-sys-color/get-sys-typeface会把每个值替换为var(--前缀-key)形式(仅shadow保留原值),这正是组件 token 引用--mat-sys-*变量的实现机制,见 _m3-tokens.scss。
_system.scss:系统级变量的实际输出
_system.scss 的多个 mixin 最终把 token 值写入 CSS:
theme-overrides($overrides):以palettes.$blue-palette与 Roboto 字体定义构建一份完整的系统 token 名列表,用于校验用户传入mat.theme-overrides((primary: red))中的键是否合法,合法则输出覆盖值system-level-colors($theme, $overrides, $prefix):按light/dark/color-scheme三种主题类型生成系统颜色(color-scheme模式下用 CSSlight-dark()同时打包浅/深两套值),并手动补入neutral-variant20、neutral10两个组件直接使用的调色板值system-level-typography:将 typescale 每个键输出为系统字体变量system-level-elevation:将高度等级与neutral0 阶阴影色组合成真实 box-shadow 后输出system-level-shape/system-level-state:分别输出圆角与状态层透明度变量
这一层正是--mat-sys-*变量在页面中可被 DevTools 观察到的最终输出者。
配套工具函数:_m3-utils.scss
_m3-utils.scss 提供三个被上层反复使用的 Sass 工具:
replace-colors-with-variant($system, $color, $variant):把系统 map 中on-<color>、on-<color>-container、<color>、<color>-container、inverse-<color>五个键的值替换为对应<variant>的取值,用于实现主题中的角色替换get-system($theme):从主题 map 中取出_mat-system系统 token 子图color-with-opacity($color, $opacity):基于color-mix(in srgb, ...)为颜色叠加透明度;若颜色本身是--开头的变量名则自动包一层var(),若透明度小于 1 的数字(如 0.38)则换算为百分比字符串
版本与维护注意点
- 本包 token 版本锁定为Material 3 v0.161,所有带版本头注释的文件均标注
Design system version: v0.161(见 _md-sys-motion.scss 等)。 - 分叉日期为 2024-07-22,此后 M3 规范的更新不会自动同步进本仓库,需要由维护者按需手动合入,因此文中所有取值均以当前仓库为准。
md-sys-color-internal与md-sys-typescale-internal是 Angular Material 预留的“规范分歧点”:当前为空 map,未来若组件需要偏离上游规范的值,应优先在此增量补充,以保持与上游 diff 的最小化。- 未使用 token 不进入本仓库(README 所述的
unused目录机制),因此当你在仓库中找不到某个上游 token 时,通常意味着该 token 未被 Angular Material 消费,不应视为缺失。
结语
m3 包是 Angular Material 主题体系中最底层的“事实来源”:六个md-sys-*-values()函数固化 Material 3 v0.161 的颜色、字体、高度、形状、状态与动效取值,_theme.scss把它们组织为_mat-systemmap,再经_m3-tokens.scss与_system.scss两层消费,最终以--mat-sys-*CSS 变量的形式呈现给组件与开发者。理解这一链路,就能在排查主题覆盖、自定义 token、或阅读组件私有 token 定义时,快速定位数值的最终出处。
【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考