ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Angular Material 主题定制完全指南:基于 Sass 的 `mat.theme` API 实现 M3 设计系统

Angular Material 主题定制完全指南:基于 Sass 的 `mat.theme` API 实现 M3 设计系统 Angular Material 主题定制完全指南基于 Sass 的mat.themeAPI 实现 M3 设计系统【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/componentsAngular Material 的主题系统借鉴了 Google Material DesignM3的设计理念允许你通过定义自定义主题来全面控制组件外观。本文基于官方 主题指南系统讲解 Angular Material v19 起引入的全新 Sass 主题 API如何编写主题文件、配置色彩/排版/密度、使用预构建主题与内置色板、实现亮暗模式切换与多主题共存并深入仓库源码tokens/_system.scss、theming/_definition.scss 等揭示其底层实现原理。读完本文你将能够从零搭建一套支持 Material 3、可切换亮暗模式、可细粒度覆盖 Design Token 的完整应用主题方案。快速上手创建你的第一个主题文件Angular Material 的主题定制从一份 Sass主题文件开始该文件必须引入mat.thememixin。这个 mixin 接收一个包含 color、typography、density 三类配置的 map并输出一组控制组件外观与布局的CSS 变量Design Tokens。颜色类变量使用 CSSlight-dark()颜色函数定义因此主题可以借助color-schemeCSS 属性在亮色与暗色模式之间自由切换。下面是一份最简主题文件应用 violet 色板、Roboto 字体和标准密度。它作用于html选择器确保 CSS 变量覆盖整个应用color-scheme显式设置为light dark让最终亮暗模式由用户系统偏好决定use angular/material as mat; html { color-scheme: light dark; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 )); }为让应用默认使用主题的 surface 背景与 on-surface 文本色可以补充如下全局样式body { background: var(--mat-sys-surface); color: var(--mat-sys-on-surface); }也可以借助mat.system-classes()生成一组 CSS 工具类直接在组件模板中套用主题样式html { ... include mat.system-classes(); }body classmat-bg-surface mat-text-on-surface需要特别注意的是mat.thememixin 只为输入 map 中包含的类别声明 CSS 变量。例如未提供typography时输出的 CSS 中不会包含排版相关变量。这一点在源码中得到印证——tokens/_system.scss 中排版变量的发射逻辑被包裹在if ($typography)分支内色彩、排版、密度三部分各自独立判断。主题配置的默认值与数据结构从 theming/_definition.scss 中define-theme函数的实现可以确认各配置项的默认值配置项默认值说明color.theme-typelight颜色取值类型color.primary$violet-palette主色板color.tertiary同 primary三级色板缺省时复用主色板typography.plain-family(Roboto, sans-serif)正文plain字体typography.brand-family同 plain品牌brand字体typography.bold-weight700粗体字重typography.medium-weight500中等字重typography.regular-weight400常规字重density.scale0密度等级主题对象内部由_mat-system系统级变量与_mat-theming-internals-do-not-access内部结构两部分组成其中系统变量通过m3-tokens模块按 M3 规范生成涵盖了颜色、排版、形状、状态、高度elevation等全套 Design Token。配置色彩Color主题的色彩决定了组件的颜色样式例如复选框的填充色、按钮的涟漪颜色等。色彩依赖一组色调渐变的色板Color Palette来构建完整的配色方案。设置颜色有两种方式单一色板或颜色 map。方式一单一色板直接传入一个色板Angular Material 会将其用作主题的 primary、secondary 和 tertiary 颜色。此时颜色值使用light-dark()CSS 函数定义因此应用样式必须显式声明color-scheme属性否则无法触发亮暗切换use angular/material as mat; html { color-scheme: light dark; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 )); }方式二颜色 map传入颜色 map 可以将 tertiary 色板与 primary 色板分开配置。tertiary 色板常用来为部分组件提供独特的强调色。同时可以通过theme-type控制颜色值的定义方式color-scheme使用light-dark()CSS 函数同时包含亮、暗两套颜色值默认行为light仅定义亮色颜色值dark仅定义暗色颜色值。light-dark()已得到所有主流浏览器的广泛支持但若应用需要兼容较旧浏览器或非主流浏览器建议显式将theme-type设为light或dark。下面示例应用 violet 主色与 orange 三级色theme-type为light即只为应用定义亮色颜色值use angular/material as mat; html { include mat.theme(( color: ( primary: mat.$violet-palette, tertiary: mat.$orange-palette, theme-type: light, ), typography: Roboto, density: 0 )); }底层实现theme-type 如何决定输出在 tokens/_system.scss 的_generate-sys-colors函数中可以看到三种theme-type的完整分支light直接返回 M3 亮色系统色dark返回暗色系统色color-scheme则对每一对亮/暗颜色值调用light-dark($light-value, $dark-value)生成可切换变量。此外如果传入的是单一色板而非 maptheme mixin 会自动把tertiary指向同一色板并将theme-type默认置为color-scheme——这与文档描述的行为完全一致。配置排版Typography排版决定组件内的文本样式例如对话框标题或菜单列表项的字体。同样有两种配置方式。方式一单一字体族直接传入字体族字符串Angular Material 会将其应用于组件所有文本。组件中使用的字重固定为粗体 700、中等 500、常规 400。方式二排版 map传入排版 map 可为plain正文与brand品牌文本设置不同字体族plain 字体用于应用大部分正文brand 字体通常用于标题与题名。map 中还可分别指定 bold、medium、regular 字重。下面示例正文使用 Roboto、品牌文本使用 Open Sans粗体 900、中等 500、常规 300色彩为 violet 色板、标准密度use angular/material as mat; html { include mat.theme(( color: mat.$violet-palette, typography: ( plain-family: Roboto, brand-family: Open Sans, bold-weight: 900, medium-weight: 500, regular-weight: 300, ), density: 0, )); }从源码看theme mixin 处理排版时若值是字符串则 plain 与 brand 共用若值是 map 则分别读取plain-family、brand-family与三个字重键最终经由system-level-typography调用m3.md-sys-typescale-values生成--mat-sys-*排版变量如--mat-sys-body-large等字体快捷变量。配置密度Density密度值决定组件内部间距例如按钮文字周围的内边距、表单字段的高度。密度值接受0 到 -5的整数0 为默认间距-5 为最紧凑布局。每下降一个整数值-1、-2……受影响尺寸减少 4px直到组件能正常渲染所需的最小尺寸为止。下面示例将密度设为 -2使大部分组件减少留白、布局更紧凑use angular/material as mat; html { include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: -2, )); }两点重要提醒密度低于 0 可能降低可访问性给使用辅助技术的用户带来导航困难密度自定义不影响出现在任务型或弹出型上下文中的组件如日期选择器。Material Design 密度规范明确不建议改变此类交互的密度因为它们并不与应用布局争抢空间。源码佐证在 tokens/_system.scss 中只有当$scale ! 0时才会输出组件级密度 Token且这些 Token如 checkbox、button、form-field 等各组件的密度变量不会回退到系统级值必须由 mixin 直接定义。使用预构建主题Prebuilt Themes如果不想通过 Sass 自定义主题Angular Material 提供了8 个预构建主题 CSS 文件其中 4 个基于现代 Material 3 设计系统另外 4 个基于旧的 Material 2 设计系统。若希望应用遵循 M3 设计语言务必选用 M3 主题M2 主题仅为向后兼容而保留将在未来版本中移除。主题设计系统亮/暗色板primary, tertiaryazure-blue.cssM3亮azure, bluerose-red.cssM3亮rose, redcyan-orange.cssM3暗cyan, orangemagenta-violet.cssM3暗magenta, violetdeeppurple-amber.cssM2亮deep-purple, amberindigo-pink.cssM2亮indigo, pinkpink-bluegrey.cssM2暗pink, blue-greypurple-green.cssM2暗purple, green预构建主题文件位于 Angular Material npm 包的prebuilt-themes目录即angular/material/prebuilt-themes。在项目angular.json的styles数组中引入所选 CSS 文件即可styles: [ angular/material/prebuilt-themes/azure-blue.css ]这些预构建主题的源码就存放在本仓库的 src/material/core/theming/prebuilt 目录下是学习完整主题定义的绝佳范例。例如 azure-blue.scss 的实现正是调用system.theme传入theme-type: light、azure 主色板、blue 三级色板与 Roboto 字体html { include system.theme(( color: ( theme-type: light, primary: palettes.$azure-palette, tertiary: palettes.$blue-palette, ), typography: Roboto, density: 0, )); }色板Color Palettes色板是一组色调相近、明度由浅到深的颜色集合。Angular Material 主题借助色板构建配色方案以传达应用的层级hierarchy、状态state与品牌brand信息。内置色板Angular Material 提供了12 个预构建色板可直接用于应用主题$red-palette$green-palette$blue-palette$yellow-palette$cyan-palette$magenta-palette$orange-palette$chartreuse-palette$spring-green-palette$azure-palette$violet-palette$rose-palette这些色板全部定义在 src/material/core/theming/_palettes.scss 中。以$violet-palette为例它包含 0~100 的色调梯度如40: #7d00fa、80: #d5baff并且通过_patch-error-palette为每个色板补充了独立的error色阶如40: #ba1a1a同时每个色板都内置secondary次要、neutral中性、neutral-variant中性变体子色板这些子色板会随主题自动参与 M3 系统色的构建见 theming/_definition.scss 中 primary/secondary/tertiary/neutral/neutral-variant/error 六类色板的组装逻辑。自定义色板Angular Material 提供了色板生成 schematic基于单个主色输入构建自定义色板并可选择性输入更多颜色以进一步定制 secondary、tertiary 与 neutral 色板ng generate angular/material:theme-color该 schematic 的详细说明见 src/material/schematics/ng-generate/theme-color/README.md其支持primaryColor、tertiaryColor、neutralColor、neutralVariantColor等选项未指定时由 Material 基于主色自动推导生成的$primary-palette、$tertiary-palette可直接接入mat.theme使用并额外提供高对比度prefers-contrast覆盖方案。加载字体Loading FontsGoogle Fonts 是加载字体的常用选项之一。例如下面的代码放在应用head中即可加载 Roboto400/500/700与 Open Sans300..800字体族link relpreconnect hrefhttps://fonts.googleapis.com link relpreconnect hrefhttps://fonts.gstatic.com crossorigin link hrefhttps://fonts.googleapis.com/css2?familyOpenSans:ital,wght0,300..800;1,300..800familyRoboto:wght400;500;700displayswap relstylesheet注意默认情况下使用 Angular CLI 创建的项目被配置为内联来自 Google Fonts 的资源以减少阻塞渲染的请求。这也解释了为什么上面的加载示例要在head中显式使用preconnect——自行引入字体时可以通过预连接减少加载延迟。支持亮色与暗色模式默认情况下mat.thememixin 使用light-dark()CSS 颜色函数定义颜色使应用能够轻松地在亮暗模式间切换。light-dark()函数依赖全局样式中声明的color-scheme值若应用未定义color-scheme则始终应用亮色。可通过color-scheme: light或color-scheme: dark显式指定模式要跟随用户系统偏好则使用color-scheme: light darkuse angular/material as mat; html { color-scheme: light dark; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 )); }另一种常见策略是把color-scheme定义在某个 CSS 选择器下使模式取决于该 class 是否被应用。下面示例中应用默认始终显示亮色主题除非给body添加dark-mode类use angular/material as mat; html { color-scheme: light; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 )); } body.dark-mode { color-scheme: dark; }Angular Material 不会根据prefers-color-scheme、prefers-contrast等用户偏好媒体查询自动应用不同样式或主题。它刻意把灵活性留给你可以依赖color-scheme: light dark也可以自定义媒体查询或读取已保存的用户偏好来应用样式。多主题Multiple Themesmat.thememixin 可以被调用多次以在应用中应用多套不同的配色方案。上下文专属主题下面的示例按上下文定制组件主题为一段删除数据提示的容器应用 cyan 色板使其中的按钮等组件获得独特、醒目的强调样式use angular/material as mat; html { include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0, )); } .example-bright-container { include mat.theme(( color: mat.$cyan-palette, )); }这种做法的底层机制是每次调用 mixin 都会在当前选择器下重新发射一组--mat-sys-*CSS 变量见 tokens/_system.scss 中current-selector-or-root的变量输出逻辑子容器内组件读取到的变量因此被局部覆盖从而实现局部换肤。使用主题样式Using Theme Styles应用的自定义组件可以直接使用mat.theme定义的 CSS 变量来应用主题的颜色与排版颜色变量适合强调重要文本与操作、强化应用品牌、确保 surface 与 on-surface 元素间有足够的对比度排版变量适合在整个应用中建立清晰的信息层级与文本一致性。下面示例演示组件使用颜色与排版变量实现一个向用户呈现重要信息的全宽横幅.my-component { background: var(--mat-sys-primary-container); color: var(--mat-sys-on-primary-container); border: 1px solid var(--mat-sys-outline-variant); font: var(--mat-sys-body-large); }也可以改用工具类达到同样的效果div classmat-bg-primary-container mat-text-on-primary-container mat-border-variant mat-font-body-lg/div这些变量与工具类的完整清单、使用场景以及组件对它们的依赖方式可参阅同仓库的 Theming your components 指南。自定义 Design TokensCustomizing TokensAngular Material 组件还允许通过overrides mixin对特定 Token 进行精准定制实现细粒度的调整——既可修改系统级主题 CSS 变量也可修改单个组件的 Token如组件边框颜色或标题字号。overrides API 会校验自定义 Token 的拼写是否正确并可在未来版本 Token 被新增、移动或重命名时用于保证向后兼容。系统级 TokenSystem Tokens通过mat.theme-overridesmixin 可更改系统级 Token它会重新定义应用中使用到的 CSS 变量。下面示例为应用应用 violet 色板但把primary-containerToken 改为特定蓝色调use angular/material as mat; html { color-scheme: light dark; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 )); .example-orange-primary-container { include mat.theme-overrides(( primary-container: #84ffff )); } }另一种方式在mat.thememixin 中传入可选的override map直接替换 mixin 应用的值use angular/material as mat; html { color-scheme: light dark; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 ), $overrides: ( primary-container: orange, )); }从源码看theme-overrides mixin 会先合并 M3 的 color/typography/elevation/shape/state 全量系统变量名然后逐个校验传入的 override 键是否存在于系统变量名集合中不存在则被忽略再以--mat-sys-*前缀输出覆盖值。同时mat.theme的$overrides参数在发射颜色、排版、高度、形状、状态各系统变量时都会优先使用 override 值如map.get($overrides, $name) or $value见 tokens/_system.scss。组件级 TokenComponent Tokens每个 Angular Material 组件都定义了各自的overridesmixin用于定制其颜色、排版与密度相关的 Token。各组件可用 Token 的完整清单可在其文档页面的Styling标签下查看。下面示例使用 Card 的overridesAPI 将背景改为红色、增大圆角、并指定更大的标题字号html { include mat.card-overrides(( elevated-container-color: red, elevated-container-shape: 32px, title-text-size: 2rem, )); }直接样式覆盖Direct Style OverridesAngular Material 支持上述方式定制颜色、排版与密度但强烈不鼓励、也不直接支持在本主题 API 之外覆盖组件 CSS。组件的 DOM 结构与 CSS 类被视为私有实现细节随时可能变化Angular Material 组件使用的 CSS 变量应通过overridesAPI 定义而不是显式自行定义。强焦点指示器Strong Focus Indicators默认情况下大多数组件通过改变背景色来指示浏览器焦点符合 Material Design 规范。但这种行为可能无法满足可访问性要求——例如 WCAG 4.5:1 要求对浏览器焦点给出更强的指示。Angular Material 支持在获得焦点的元素上渲染高可见度轮廓。应用通过调用mat.strong-focus-indicators()启用use angular/material as mat; html { color-scheme: light dark; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 )); include mat.strong-focus-indicators(); }默认情况下焦点指示器使用主题的secondary 颜色可通过调用strong-focus-indicators-theme($color)mixin 自定义颜色也可在默认颜色与背景对比度不足的场景下用它更换焦点指示器颜色。自定义强焦点指示器可以向strong-focus-indicators传入配置 map 自定义指示器外观支持border-color、border-style、border-width与border-radius四个配置项use angular/material as mat; include mat.strong-focus-indicators(( border-color: red, border-style: dotted, border-width: 4px, border-radius: 2px, ));源码实现见 focus-indicators/_private.scssmixin 的默认配置为border-color: var(--mat-sys-secondary, black)与display: block用户配置会与默认配置合并同时该 mixin 还会为标准 chips 的内部结构补上overflow: visible以避免与焦点指示器的渲染冲突。在 Shadow DOM 中使用主题Angular Material 默认假设所有主题样式以全局 CSS方式加载。如果应用要使用 Shadow DOM则必须在每个包含 Angular Material 组件的 shadow root 内加载主题样式。可以通过两种方式实现在每个 shadow root 中手动加载 CSS使用 Constructable Stylesheets 在 shadow root 间共享主题样式。总结一套主题方案的完整决策路径综合全文搭建 Angular Material 主题的决策路径可以归纳为四步选择主题来源若追求开箱即用直接在angular.json引入 预构建主题推荐 M3 主题若需要品牌化定制则编写 Sass 主题文件调用mat.theme确定配色从 12 个内置色板 中选择或通过ng generate angular/material:theme-color生成自定义色板并按需通过颜色 map 区分 primary/tertiary 与theme-type确定排版与密度选择单一字体族或 plain/brand 双字体方案权衡密度 0~-5 对布局紧凑度与可访问性的影响细化与兼容借助mat.theme-overrides与组件级overridesmixin 微调 Token通过color-scheme实现亮暗模式调用strong-focus-indicators强化可访问性并在 Shadow DOM 场景下正确分发主题样式。每一步的底层行为默认值、light-dark()生成逻辑、Token 校验、密度变量发射等都可以在 tokens/_system.scss、theming/_definition.scss 与 focus-indicators/_private.scss 等源码文件中找到对应实现方便你在遇到边界问题时深入排查。【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表