
把 Material 3 当成会跟着壁纸变色的换肤功能是我见过最多的误解。去年我把 Material Design 3 官方设计指南完整过了一遍又在一款日活几十万的产品里把主题从 M2 迁到了 M3才意识到这套设计语言真正厉害的地方不在动态取色而是它把个性化表达和设计系统这两个本来有点矛盾的方向拧成了一股绳。这篇笔记是我啃完 M3 指南之后整理的精华里面掺了不少自己落地时的实测体会。适合三类人看准备做 Android 端改版的产品设计师、在 Figma 里搭 M3 设计系统的 UI 设计师、以及想知道设计规范为什么这么定的客户端开发。我不打算把官方文档翻译一遍而是挑那些文档里没说透、但实际项目里最容易出问题的地方展开。1. M3 的设计逻辑转向从统一规范到个性表达1.1 Material You 到底 You 在哪里M2 时代的设计语言核心是统一和规则。所有 App 用同一套蓝色、同一套阴影、同一套组件比例换来的是极强的辨识度和较低的决策成本。代价也很明显产品之间越来越像个性化只能靠插画和运营位硬撑。M3 把关键词换成了 expressive、personalization、adaptive。Material You 这个命名里的You指的不是设计师而是终端用户——系统不再由设计规范单方面规定你必须是这个颜色而是根据用户的使用场景、壁纸、甚至是用户主动选择的内容动态生成一套视觉主题。注意这里的关键不是换肤而是生成规则颜色不是设计师手挑的几个色值而是通过算法从一个种子色seed color推导出来的完整体系。这个转向对设计工作流的影响是结构性的。以前我们交设计稿交付的是一组颜色现在交的是一条颜色生成链路加链路出问题时的兜底策略。我刚做迁移时老用旧思维改色板改到一半就发现只要 seed color 一变整套色板都会跟着变手动微调的意义很小。你得先接受这个新逻辑再谈具体落地。1.2 设计令牌M3 的底层地基M3 整个系统都是建立在设计令牌design tokens之上的。颜色有颜色令牌形状有形状令牌字体有字体令牌连高度和状态层都有自己的 token 体系。为什么要强调这一点因为 M3 的组件规范和实现代码之间靠的正是这层抽象。你在 Figma 里看到的 M3 组件库本质上是一个长着 M3 外观的令牌驱动组件——改一个主色 token全局按钮、卡片、导航栏全部跟着变。到了代码侧Jetpack Compose 的 Material3 库和传统 XML 的 Material Components for Android 1.5 也都实现了同一套 token 体系。实际操作中这意味着改主题不再等于改组件。M2 时代换主题色经常要逐个检查按钮、输入框、选中态有没有漏改M3 时代你只要维护好 token 的映射关系组件会自动收敛。我后来在 Figma 里搭组件库时把所有颜色引用全部指向 style 变量而不是直接填色值改版的效率提升非常明显。如果你现在还是一个组件一个组件地上色建议先停一下把 M3 这套令牌思维建立起来再动手。2. 动态配色推演链一个种子色如何长成整套主题2.1 种子色 → 14 级音调色板 → 色彩角色M3 动态配色的完整链路是这样的你先给一个 seed color种子色Material Color Utilities 库会把种子色映射到 HCT 色彩空间然后生成 14 个明度档位的音调色板tonal palette。这 14 个档位从 0 到 100分别是 0、10、20、25、30、40、50、60、70、80、90、95、99、100。注意不是均匀分布的中间密两端疏因为人眼对中间区域的明度变化更敏感。整个系统会生成五个基准色板primary品牌主色对应系统里的主操作、选中态secondary次要强调色用于辅助操作和低权重强调tertiary第三强调色纯粹为了表达力而存在用来制造视觉层次neutral中性色承载 surface、background 等大面积底色neutral-variant中性变体用于次要文字、描边、分割线每个色板都能在 14 个音调上取值这就引出下一步——色彩角色。2.2 色彩角色是语义不是色值M3 最容易被新手忽略的地方是它把颜色从具体色值升级成了语义角色。也就是说你在设计稿里不应该说这个按钮是 #6750A4而应该说这个按钮的容器是 primary。常见的色彩角色有这么几组角色典型用途说明primary / on-primary主按钮、选中态on-* 表示放在该颜色上面的内容颜色primary-container / on-primary-container次级强调容器比 primary 浅一档常用于选中卡片secondary / tertiary辅助强调M3 特色给界面更多层次surface / on-surface页面底色与主文字surface 是中性色不带彩度surface-variant / on-surface-variant次要底色与次要文字比 surface 略深适合分组背景outline / outline-variant描边、分隔线替代 M2 时代部分 divider 用法surface-container-low 到 highest卡片层级底色用容器明度表达层级替代阴影这套语义体系的妙处在于当 seed color 变化时primary 的色值变了但主按钮该用什么颜色这个语义没变所以组件不会错乱。反过来说如果你在项目里用浅紫色深灰色这种描述来维护颜色那 M3 的迁移前期就得花大力气把词表统一掉。我踩过的一个具体坑是直接把旧品牌色往里塞进 primary 角色结果对比度一塌糊涂。后来才明白primary 角色只负责语义品牌色的表达应该交给 primary-container 或动态取色之后的色板而不是咬着原始色值不放。2.3 实操笔记品牌色被稀释的补救办法品牌团队通常会很在意品牌蓝必须是 #1565C0这件事。M3 的动态取色天然会稀释品牌色因为算法是从种子色推导整个色板出来的 primary 不可能是原来的精确色值。我的处理办法分三步把品牌色作为 seed color 输入生成 baseline scheme基线方案不要手动造色板。对必须保持品牌辨识度的场景比如 Logo、品牌页背景使用静态色资源不走动态角色。如果主 CTA 在动态取色后对比度不足黄色、橙色种子色特别容易翻车把 CTA 固定到静态 primary或者转移到容器角色 足够深的 on-primary-container组合上。另外一定要在各种壁纸下做多主题测试。动态取色在浅色壁纸上可能给出很浅的色板深色壁纸又可能给出过饱和的色板这两个极端场景都得有兜底规则。Figma 的官方 Material Theme Builder 插件可以直接预览种子色变化带来的全组件效果建议选种子色时就在里面调别在 Sketch 里脑补最后效果。补充一个 HCT 色彩空间的知识点M3 之所以不用我们熟悉的 HSL/HSB是因为 HSB 在感官上不均匀——同样改 10 个单位的饱和度蓝色看起来变化不大橙色却已经刺眼了。HCT 把色调Hue、色度Chroma、明度Tone分开建模其中 Tone 方向的变化在感知上是均匀的。这就是为什么 M3 的调色板不会出现某个颜色突然变艳或者变脏的情况整套配色体系能保持统一质感。3. 形状、状态层与音调高度M3 组件变软的三层机制很多人第一眼看到 M3 的感觉是变圆了、变软了。这个观感不是随便来的而是三层底层机制同时作用的结果新的形状令牌体系、状态层的引入、以及用音调高度替代纯阴影。3.1 一套形状令牌覆盖所有组件M3 定义了一套从无圆角到全圆角的形状尺度共 7 档none0dp、extra small4dp、small8dp、medium12dp、large16dp、extra large28dp、full完全圆角。所有组件的圆角都从这 7 档里取值。比如按钮类组件通常用 full所以 M3 的填充按钮看起来是胶囊形卡片多用 medium 到 large输入框、列表项偏 small 到 medium对话框用 extra large 到 fullM2 时代圆角的取值比较随意——同一个卡片在不同 App 里有 4dp、8dp、12dp 各种尺寸团队内部对齐成本很高。M3 把圆角抽象成形状令牌之后主题切换时只需要改一套形状变量所有组件同步变化。这跟颜色令牌的逻辑完全一样语义化、变量化、一处修改全局生效。3.2 状态层按压、悬停、拖拽的透明度标准M3 的交互状态反馈是一个很容易被忽略但极其重要的机制状态层。它不再是按下去换个背景色而是在组件之上叠加一层半透明遮罩通过透明度表达当前状态。官方给出的标准透明度如下状态状态层透明度Hover悬停8%Focus聚焦10%Pressed按压10%Dragged拖拽16%为什么这样做更合理因为 M2 的做法是直接改组件底色浅色主题和深色主题需要分别设计两套按压色很容易漏。M3 的状态层是叠加在任意 surface 颜色之上的只要底色支持叠加深浅主题下反馈的感知强度会保持一致。这在设计系统层面是一个巨大的维护成本节约。实际落地时注意状态层用的是颜色的 alpha 通道别在 Figma 里直接改填充色。M3 官方组件库里这些都已经封装好但如果团队是自建组件库一定要把状态层做成组件属性hover、focused、pressed、dragged让使用方直接调用而不是手工拉透明度。不然做出来的效果在暗色模式下会明显偏深或者偏脏。3.3 音调高度用色调取代阴影M3 最让我觉得反直觉的改动是用音调高度tonal elevation来部分替代阴影。传统设计中层级靠阴影表达卡片阴影越重离页面越高。但深色模式下阴影几乎不可见层级就垮了。M3 的解法是做了一层面染色surface tintsurface 颜色本身会叠加一层来自 primary 的轻微色调层级越高叠加越明显。具体来说M3 定义了 0 到 5 共六个高度层级每升一级surface 上叠加的色调就越深一点点。于是卡片的层级不再只靠投影而是靠底色深浅 描边 轻阴影的组合来表达。我在实际设计里体会最深的是M3 的卡片在一张白色页面上看起来是一张稍微带点灰紫色的浅色浮层而不是一个以阴影撑起来的白色方块。这个差异在深色模式下尤其明显——深色主题里卡片和背景的区分度几乎完全靠 tonal elevation 维持阴影反而成了配角。做深色模式时别把 M2 那套深灰底 更深灰卡片 阴影直接搬过来。先检查你的 surface 容器层级色有没有拉开这个优先级高于调阴影。4. 字阶表重构15 个样式背后的排版逻辑4.1 五类三级Display、Headline、Title、Body、LabelM3 的字体系统从 M2 的 12 个样式重构为 15 个样式分为五类每类大中小三档类别大中小Display57 / 6445 / 5236 / 44Headline32 / 4028 / 3624 / 32Title22 / 2816 / 24字重 50014 / 20字重 500Body16 / 2414 / 2012 / 16Label14 / 20字重 50012 / 16字重 50011 / 16字重 500表格里第一个数字是字号sp第二个是行高sp。默认字体是 Roboto但 M3 对字体本身没有强绑定核心是这套节奏关系。4.2 和 M2 的对比哪些字号变了、为什么M2 里有个 overline 样式全大写小字号常用于列表分类标签M3 把它并进了 Label 体系。M2 的 subtitle 两档并进了 Title 体系。最大的变化是 Display 序列——M3 最大字号拉到了 57sp明显是为了适配大屏设备、折叠屏和沉浸式浏览场景。以前我们做手表、手机、平板共用一套字阶会有点紧张M3 给大屏留足了空间。另外注意字重变化M2 的标题大量使用 Medium500M3 的 Display 和 Headline 类都回归了 Regular400只有 Title 和 Label 类保留 Medium。这个变化很微妙但影响很大——M3 的标题看起来更轻盈、更透气正文和标题的界限不再只靠字号而是靠字重和行高共同建立的节奏。4.3 落地建议与常见误用我在项目里总结出三条实用规则正文优先选 Body Large 或 Body Medium。Body Small12sp虽然省空间但作为正文阅读体验已经很吃力了只适合辅助信息。Display 别乱用。很多人看到 57sp 觉得震撼恨不得首屏放个 Display Large结果页面信息密度暴跌。Display 类适合启动页、空状态、品牌表达页这几个少数场景。适配系统字体缩放。Android 上 sp 单位会跟随系统字号设置变化超大字号模式下布局很容易被撑爆。M3 指南要求文本在系统放大 200% 时依然完整可用建议用 maxLines ellipsis 控制并给关键文本区域留足换行空间。还有一个细节M3 的图层面板里Label 类样式一般都带字距tracking比如 Label Large 的字距是 0.1Body Large 是 0.5。Figma 里如果从 M2 项目复制文本过来字距设置可能残留旧值肉眼看起来不太对但又说不出哪里不对。迁移时建议把字阶的 tracking 统一重置成 M3 标准值。5. 组件变化速查与迁移实操记录5.1 重点组件变化清单M3 对组件库做了不少改名字、调形态、加变体的操作这里列一份快速对照M2 组件M3 对应主要变化Contained ButtonFilled Button圆角变大高度 40dp胶囊化无Filled Tonal Button新增用 secondary-container 背景适合次级 CTAText Button / Outlined Button保留形态微调状态层机制统一FAB / Mini FABFAB / Small FAB / Large FAB / Extended FAB新增 Small40dp和 Large96dpBottom NavigationNavigation Bar高度统一 80dp采用新的指示条样式无Navigation Rail新增适合平板和横屏Top App BarSmall / Medium / Large 三档支持折叠和标题缩放动效Switch保留但重绘轨道加图标圆润度大幅提升Snackbar保留但重绘圆角变化明显默认用 full 圆角无Badge新增小组件替代红点 数字的零散方案这份清单不用背重点是理解变化的逻辑M3 整体朝着更圆、更轻、更多层级的方向走。按钮从 36dp 加到 40dp、导航从扁平 tab 变为带指示条的 bar都是为了在触屏和视觉识别之间取得更好的平衡。5.2 迁移到 M3 的推荐顺序从 M2 迁 M3别指望一天搞定。我推荐的顺序是先用 Material Theme Builder 生成 baseline 主题 token把颜色、形状、字阶三套 token 建好。把页面底色的语义从白色/深灰色改成 surface 系列角色这是后续所有改动的基础。替换高感知组件按钮、导航栏、输入框、卡片。统一状态层把 hover / focus / pressed / dragged 都接到组件属性上。最后处理大标题、动效、Badge 这类锦上添花的东西。代码侧的话Jetpack Compose 直接用 material3 库改一个 colorScheme 就能切换主题XML 项目需要升到 Material Components for Android 1.5.0 以上然后应用 Theme.Material3.* 主题。建议先在分支上做一个最小 Demo把主题切过去看看所有页面的脸色再决定是全局改还是渐进式改。5.3 迁移实测踩过的三个坑第一个坑是误把动态取色当成全站换肤。团队一开始以为所有元素都会智能适配用户壁纸结果测试时发现某个页面里图表配色和壁纸撞色了。核心原因是图表颜色不应该用动态角色需要独立维护一套语义色。记住动态取色只影响色彩角色不改变你为特定业务场景预留的静态色策略。第二个坑是Figma 组件库的旧 token 残留。从 M2 切换到 M3 组件库时旧页面上有些样式还指向老的命名比如 Primary 之类开发照着还原颜色就出现了偏差。后来我把所有样式清理了一遍强制所有组件引用新的 token 名并且跑了一次截图回归对比才解决。迁移不只是换组件还要清命名空间。第三个坑是对比度问题。M3 的 primary-container 在某些种子色下和 on-primary-container 的对比度达不到 WCAG AA 标准尤其是橙色、黄色系种子色。这会导致浅色文字在浅色容器上很难看清。这属于设计系统层面的硬伤不能靠调一下透明度蒙混过关要么换种子色要么对该角色使用固定色值。最后说点个人的体会。M3 这套设计的门槛其实比 M2 高——它要求设计师理解语义化令牌化算法生成这些偏工程的思维而不是单纯地挑颜色、摆组件。但也正因为门槛高做出来的东西一旦跑通产品之间的辨识度和质感差异会非常明显。如果你正准备迁移别急着追求 100% 还原官方 spec先把色彩角色、状态层、音调高度这三个底层语义理清楚组件长什么样反而是最后一步的事。