Angular Material 18+ 高级教程 – Custom Themes for Material Design 3 (自定义主题 Material 3)
v18 更新重要说明
从 Angular Material v18 开始,默认使用的是 Material 3 Design (简称 M3)。
而且是正式版,不再是 experimental preview 了。
由于本篇写的时候是 v17,而我现在没力修改下面的 demo 代码,所以这里 highlight 一下 breaking changes 就好:
-
不需要 @angular/material-experimental
@use '@angular/material-experimental' as matx;
直接用 @angular/material 即可
@use '@angular/material' as mat;
-
不需要 m3 prefix 了,比如
matx.$m3-blue-palette 换成 mat.$blue-palette
-
如果是用 m2 版本,反而要加上 prefix m2
mat.define-dark-theme 换成 mat.m2-define-dark-theme
前言
续上一篇的 Custom Themes for Material Design 2 (简称 M2) 之后,我们继续看 Material Design 3 (简称 M3)。(提醒:没有看过 M2 的朋友请先看 M2 的哦)
Angular Material v17.2.0 发布了对 Material Design 3 的实现 (preview 版本)。
M2 和 M3 主要只是样式不同而已,组件的交互,使用接口等等全部都一样,所以你也可以把它理解为只是换了一个默认主题 (Theme)。
参考
Angular Material Docs – Material 3 Theming
Material Design Docs – Color System
Material Design Docs – Typography
Angular Material Design 3 Get Started
首先添加 Angular Material
ng add @angular/material
选择 Custom Theme
添加 @angular/material-experimental 包
yarn add @angular/material-experimental
App Template
<mat-card> <mat-card-header> <mat-card-title>Title</mat-card-title> <mat-card-subtitle>Subtitle</mat-card-subtitle> </mat-card-header> <mat-card-content> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium, iusto?</p> <div class="button-list"> <button mat-raised-button color="primary">Primary</button> <button mat-raised-button color="accent">Accent</button> <button mat-raised-button color="warn">Warn</button> </div> </mat-card-content> </mat-card>
App Styles (美化一下而已)
mat-card { max-width: 360px; mat-card-content { padding: 16px; .button-list { margin-top: 16px; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; } } }
styles.scss (先来个 M2 版本)
@use '@angular/material' as mat;
@include mat.core();
$m2-primary: mat.define-palette(mat.$indigo-palette);
$m2-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
$m2-warn: mat.define-palette(mat.$red-palette);
$m2-typography: mat.define-typography-config();
$m2-theme: mat.define-light-theme((
color: (
primary: $m2-primary,
accent: $m2-accent,
warn: $m2-warn,
),
typography: $m2-typography
));
@include mat.all-component-themes($m2-theme);
效果
styles.scss (M3 版本)
@use '@angular/material' as mat; @use '@angular/material-experimental' as matx; @include mat.core(); $m3-theme: matx.define-theme(( color: ( theme-type: light, primary: matx.$m3-blue-palette, tertiary: matx.$m3-red-palette, ), typography: ( plain-family: 'Roboto', brand-family: 'Roboto', bold-weight: 700, medium-weight: 500, regular-weight: 400 ), density: ( scale: 0 ) )); html { @include mat.all-component-themes($m3-theme); }
效果
M2 和 M3 的风格差别挺大的,圆角更明显了,颜色运用不太一样,字体尺寸也有微调。
不过这些我都不关心,毕竟我不是设计师,看不出哪一个比较好。
对比 Material 2 和 Material 3
首先是 M3 需要引入多一个包 @angular/material-experimental
@use '@angular/material' as mat;
@use '@angular/material-experimental' as matx;
当然,它依然需要 @angular/material 包,因为 M3 并不是一个全新的 Material Design 实现,它只是一个新主题而已。
Define Color Theme
$m3-color-theme: matx.define-theme((
color: (
theme-type: light,
primary: matx.$m3-blue-palette,
tertiary: matx.$m3-green-palette,
)
));
M3 和 M2 有几个区别:
-
M2 有 define-light-theme 和 define-dark-theme 两个方法。
而 M3 只有一个 define-theme 方法,取而代之的是它的 color 参数有一个 theme-type 属性用来表达是 light theme or dark theme。
-
M2 可以配置 primary, accent, warn 三个颜色
M3 只可以配置 primary 和 tertiary 两个颜色
这个 tertiary 相等于 M2 的 accent,而 M2 的 warn 在 M3 叫 error。
-
M3 目前不支持 Custom Base Palette (M2 支持),我们只能选择几个固定的颜色
Define Typography Theme
$m3-typography-theme: matx.define-theme((
typography: (
brand-family: 'Roboto',
plain-family: 'Roboto',
bold-weight: 700,
medium-weight: 500,
regular-weight: 400
),
));
M3 和 M2 有几个区别:
-
M3 不允许调整 Type Scale Level
-
M3 只允许调整 5 个属性
brand-family 用于 headline
plain-family 用于 paragraph
regular, medium, bold 用于 font-weight
-
M3 的 Type Scale Level 有新的命名和尺寸
它分 5 个大 Level:Display,Headline,Title,Body,Label
大 Level 里又分小 Level:Large,Medium,Small
Define Density Theme
$m3-density-theme: matx.define-theme((
density: (
scale: 0
)
));
scale 最大是 0,最小是 -3
Apply Theme to Components
M3 apply theme 的方式和 M2 大同小异。
html { @include mat.all-component-bases($m3-theme); }
唯一的区别是 M3 一定要 under 某个 selector。通常放 html {} 或者 :root 都可以。
mat.all-component-bases 输出的是 CSS Variables,这点 M2 和 M3 都是一样的。
apply theme 1 by 1:
html { @include mat.all-component-bases($m3-base-theme); @include mat.all-component-colors($m3-color-theme); @include mat.all-component-typographies($m3-typography-theme); @include mat.all-component-densities($m3-density-theme); }
apply components 1 by 1:
html { @include mat.button-base($m3-base-theme); @include mat.button-color($m3-color-theme); @include mat.button-typography($m3-typography-theme); @include mat.button-density($m3-density-theme); }
Color Variants
眼尖的朋友或许会发现到 color 属性失灵了
<button mat-raised-button color="primary">Primary</button> <button mat-raised-button color="accent">Accent</button> <button mat-raised-button color="warn">Warn</button>
三个 Button 的颜色都是 primary。
<button mat-raised-button color="tertiary">Accent</button> <button mat-raised-button color="error">Error</button>
即便换成最新的命名效果也是一样。
这是因为,M3 不再自动输出相关代码。
我们看看 M2
@include mat.button-color($m2-theme);
M2 会自动输出下面这几段
M3 则不会了。
解决方法有 2 个:
-
自己补上
html { .mat-mdc-raised-button.mat-tertiary { @include mat.button-color($m3-color-theme, $color-variant: tertiary); } .mat-mdc-raised-button.mat-error { @include mat.button-color($m3-color-theme, $color-variant: error); } }
<button color="tertiary"> Angular Material 会自动添加 class mat-tertiary
-
使用向后兼容方法
html { @include matx.color-variants-back-compat($theme); }
color-variants-back-compat 是 Angular Material 特别为了方便向后兼容而设的。
它的源码在 _color-api-back-compat.scss
最终也是使用了 @include mat.button-color($m3-color-theme, $color-variant: tertiary)
Custom component reads theme information
M2 和 M3 大同小异,方法是同一个,只是参数有些换了而已。
Reads color theme information
依然是使用 mat.get-theme-color 方法,但是参数不一样。
它有两种调用方式:
Reading tonal palette colors
第一种调用方式是传入 3 个参数,这个叫 Reading tonal palette colors。
参数一是 $m3-theme
参数二是 Palette Name,选项有:
- primary
- secondary
- tertiary
- error
- neutral
- neutral-variant
参数三是明度 Level,选项有:
- 0
- 10
- 20
- 30
- 40
- 50
- 60
- 70
- 80
- 90
- 95
- 99
- 100
Reading color roles
第二种调用方式是传入 2 个参数,这个叫 Reading color roles。
参数一是 $m3-theme
参数二是 Role Name:
primary
on-primary
primary-container
on-primary-container
primary-fixed
primary-fixed-dim
on-primary-fixed
on-primary-fixed-variant
secondary
on-secondary
secondary-container
on-secondary-container
secondary-fixed
secondary-fixed-dim
on-secondary-fixed
on-secondary-fixed-variant
tertiary
on-tertiary
tertiary-container
on-tertiary-container
tertiary-fixed
tertiary-fixed-dim
on-tertiary-fixed
on-tertiary-fixed-variant
error
on-error
error-container
on-error-container
surface-dim
surface
surface-bright
surface-container-lowest
surface-container-low
surface-container
surface-container-high
surface-container-highest
on-surface
on-surface-variant
outline
outline-variant
inverse-surface
inverse-on-surface
inverse-primary
scrim
shadow
想多了解 Color Roles 可以看这篇 Docs – Color roles。
举个例子,我们设定的 primary color 被用于 Container (通常指 background-color) 时,它的颜色并不是 primary 而是会浅一点。
On Primary Container 的 On 指的是 On Top,也就是 bg-color 和 color 的 contrast 关系。
M3 的颜色用法和 M2 不太一样,M2 我们会拿 primary default,primary lighter,而 M3 我们不太会拿 primary 50,取而代之的是直接拿 primary-container。
另外,M2 可以拿组件 (e.g. dialog, button) 的 foreground 和 background,M3 则不行。
Apply alpha to color
mat.get-theme-color 方法返回的是 HEX (hexadecimal),如果想加入 alpha 可以利用 alpha hexadecimal (#RRGGBBAA)。
background-color: #{mat.get-theme-color($m3-color-theme, primary)} + '09'; --background-color: #{mat.get-theme-color($m3-color-theme, primary)}09;
如果想更灵活可以把 hex 转换成 hsl (提醒:转换后颜色可能会有微差哦)
$color: mat.get-theme-color($m3-color-theme, primary); $hue: color.hue($color); $saturation: color.saturation($color); $lightness: color.lightness($color); app-root { --primary-hsl-value: #{$hue} #{$saturation} #{$lightness}; background-color: hsl(var(--primary-hsl-value) / 50%); }
Reads typography theme information
和 M2 一样使用 mat.get-theme-typography 方法,参数也一样,只是 Scale Level Name 换了。
M3 Scale Level Name:
display-large
display-medium
display-small
headline-large
headline-medium
headline-small
title-large
title-medium
title-small
body-large
body-medium
body-small
label-large
label-medium
label-small
Reads density theme information
和 M2 一摸一样,这里就不复述了。
总结
1. M3 是建立在 M2 基础上的,所以必须先掌握 M2
2. M3 主要是改了 Styles (CSS) 的部分,组件交互 (TS) 的部分完全没有变动。
2. M3 的颜色运用和 M2 区别比较大,这个是 Material Design 的知识,多参考 Material Design 3 Color System
3. M3 的 Typography 不能自定义 Type Scale Level 尺寸了,而且 Type Scale Level Name 都换了。
4. M3 目前是 preview 版本,不过相信 Angular Material v18 就会变成稳定版了,因为它也不算是大改。
M3 给我的感觉是限制更多了,能自定义的地方更少了。
目录
上一篇 Angular Material 18+ 高级教程 – Custom Themes for Material Design 2 (自定义主题 Material 2)
下一篇 Angular Material 18+ 高级教程 – CDK Portal
想查看目录,请移步 Angular 18+ 高级教程 – 目录
喜欢请点推荐👍,若发现教程内容以新版脱节请评论通知我。happy coding 😊💻