Angular Material 2 自定义主题

1. 什么是 theming

Angular Material 的主题系统可让您为应用程序中的组件自定义基础样式、颜色、排版和密度样式。主题系统基于 Google 的 Material Design 规范。

本文档介绍了自定义颜色的概念和 API。对于排版自定义,请参阅Angular Material Typography。有关构建可使用此系统进行自定义的组件的指南,请参阅主题化您自己的组件

2. Sass

Angular Material 的主题 API 是使用 Sass 构建的。本文档假设您熟悉 CSS 和 Sass 基础知识,包括变量、函数和 mixin。

您可以通过使用预构建主题来使用不带 Sass 的 Angular Material,如 下面的使用预构建主题中所述。但是,直接使用库的 Sass API 可以让您最大程度地控制应用程序中的样式。

3. 调色板

调色板是代表颜色空间一部分的颜色的集合。该集合中的每个值称为色调。在 Material Design 中,调色板中的每种色调都有一个标识符号。这些标识符数字包括 50,然后是 100 到 900 之间的每 100 个值。这些数字将调色板内的色调从最亮到最暗进行排序。

Angular Material 使用一个Sass map对象来表示调色板。该对象包含调色板的色调以及每种色调的对比色的另一个嵌套贴图。当使用色调作为背景色时,对比色用作文本颜色。下面的示例演示了调色板的结构。有关更多背景信息,请参阅 Material Design 颜色系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$indigo-palette: (
50: #e8eaf6,
100: #c5cae9,
200: #9fa8da,
300: #7986cb,
// ... continues to 900
contrast:
(
50: rgba(black, 0.87),
100: rgba(black, 0.87),
200: rgba(black, 0.87),
300: white,
// ... continues to 900
),
);

3.1. 创建您自己的调色板

您可以通过定义与上面调色板部分中描述的结构相匹配的 Sass 映射来创建自己的调色板 。该贴图必须定义 50 种色调以及 100 到 900 之间的每一百种色调。该贴图还必须 contrast 为每种色调定义具有对比色的贴图。

您可以使用Material Design 调色板工具来帮助选择调色板中的色调。

3.2. 预定义调色板

Angular Material 提供基于 2014 版 Material Design 规范的预定义调色板。有关完整列表,请参阅Material Design 2014 调色板

除了编号从 0 到 900 的色调外,2014 年 Material Design 调色板还包含编号为 A100、A200、A400 和 A700 的不同强调色调。 Angular Material 不需要这些色调,但您可以在定义主题时使用这些色调,如下面的定义主题中所述。

1
2
3
@use "@angular/material" as mat;

$my-palette: mat.$indigo-palette;

4. 主题

主题是颜色、排版和密度选项的集合。每个主题都包含三个用于确定组件颜色的调色板:

  • 在整个应用程序中最常出现的颜色的主调色板
  • 用于有选择地突出显示 UI 的关键部分的强调色或辅助调色板。
  • 用于警告和错误状态的警告或错误调色板

您可以通过以下两种方式之一在应用程序中包含主题的 CSS 样式:使用 Sass 定义自定义主题,或导入预构建的主题 CSS 文件。

4.1. 使用 Sass 自定义主题

主题文件是一个 Sass 文件,它调用 Angular Material Sass mixin 来输出颜色、排版和密度 CSS 样式。

4.2. core mixin

Angular Material 定义了一个名为 core 的 mixin,其中包含多个组件使用的常见功能(例如波纹)的必备样式。core 即使您定义了多个主题,mixin 也必须在您的应用程序中包含一次。core 多次包含 mixin 会导致应用程序中出现重复的 CSS。

1
2
3
@use "@angular/material" as mat;

@include mat.core();

4.3. 定义主题

Angular Material 将主题表示为 Sass map,其中包含颜色、排版和密度选择,以及一些基本的设计系统设置。有关自定义排版的深入指南,请参阅 Angular Material Typography 。有关调整组件密度的详细信息,请参阅 下面的自定义密度。

构建主题首先需要定义主要调色板和强调调色板,以及可选的警告调色板。 Sass 函数 define-palette 接受一个调色板(如 上面的调色板部分所述)以及四个可选的色调数字。这四种色调按顺序表示:“默认”色调、“较亮”色调、“较暗”色调和“文本”色调。组件使用这些色调来为自身的不同部分选择最合适的颜色。

1
2
3
4
5
6
7
@use "@angular/material" as mat;

$my-primary: mat.define-palette(mat.$indigo-palette, 500);
$my-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);

// The "warn" palette is optional and defaults to red if not specified.
$my-warn: mat.define-palette(mat.$red-palette);

您可以通过调用 define-light-theme 或 define-dark-theme 以及 efine-palette 的结果来构建主题。浅色主题与深色主题的选择决定了整个组件使用的背景色和前景色。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@use "@angular/material" as mat;

$my-primary: mat.define-palette(mat.$indigo-palette, 500);
$my-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);

// The "warn" palette is optional and defaults to red if not specified.
$my-warn: mat.define-palette(mat.$red-palette);

$my-theme: mat.define-light-theme(
(
color: (
primary: $my-primary,
accent: $my-accent,
warn: $my-warn,
),
typography: mat.define-typography-config(),
density: 0,
)
);

4.4. 将主题应用到组件

Sass core-theme mixin 为多个组件使用的常见功能(例如波纹)准备一些基本的样式。每个主题必须包含此 mixin 一次。

每个 Angular Material 组件都有一个针对每个主题维度的 mixin :基础、颜色、排版和密度。例如,MatButton 声明 button-base、button-color、 button-typography 和 button-density。每个 mixin 仅生成与该定制维度相对应的样式。

此外,每个组件都有一个“主题”mixin,它生成依赖于主题配置的所有样式。如果您向 define-light-theme 或 define-dark-theme 提供了相应的配置,则此主题 mixin 仅生成颜色、版式或密度样式,并且它始终生成基本样式。

通过包含每个主题 Sass mixins 来为应用程序中使用的每个组件应用样式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@use "@angular/material" as mat;

@include mat.core();

$my-primary: mat.define-palette(mat.$indigo-palette, 500);
$my-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);

$my-theme: mat.define-light-theme(
(
color: (
primary: $my-primary,
accent: $my-accent,
),
typography: mat.define-typography-config(),
density: 0,
)
);

// Emit theme-dependent styles for common features used across multiple components.
@include mat.core-theme($my-theme);

// Emit styles for MatButton based on `$my-theme`. Because the configuration
// passed to `define-light-theme` omits typography, `button-theme` will not
// emit any typography styles.
@include mat.button-theme($my-theme);

// Include the theme mixins for other components you use here.

为了简化配置,在使用 Angular material 的过程中不必单独为每个组件的设置样式,Angular Material 提供了,其中包含库中所有组件设置样式的 Sass mixin:all-component-bases、 all-component-colors、all-component-typographies、all-component-densities 和 all-component-themes。这些 mixins 的行为与单个组件 mixins 相同,只不过它们为 Angular Material 中的所有 35+ 组件的 core-theme 生成样式。除非您的应用程序使用每个组件,否则这将产生不必要的 CSS。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@use "@angular/material" as mat;

@include mat.core();

$my-primary: mat.define-palette(mat.$indigo-palette, 500);
$my-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);

$my-theme: mat.define-light-theme(
(
color: (
primary: $my-primary,
accent: $my-accent,
),
typography: mat.define-typography-config(),
density: 0,
)
);

@include mat.all-component-themes($my-theme);

要在应用程序中包含生成的样式,请将主题文件添加到项目的 angular.json styles file 数组中。

4.5. 主题内容

Angular Material 主题分为四个维度的内容:基础、颜色、排版和密度。

4.5.1. 基础(base)

设计系统的通用基本样式。这些样式不会根据您配置的颜色、排版或密度而改变,因此每个应用程序只需包含一次它们。这些 mixin 包括结构样式,例如 border-radius、border-width 等。所有组件都有一个基本 mixin,可用于包含其基本样式。 (例如, @include mat.checkbox-base($theme))

4.5.2. 颜色 (color)

与应用程序中的颜色相关的样式。这些样式应至少包含在您的应用程序中一次。根据您的需要,您可能需要使用不同的配置多次包含这些样式。 (例如,如果您的应用程序支持浅色和深色主题颜色。)所有组件都有一个颜色混合,可用于包含其颜色样式。 (例如, @include mat.checkbox-color($theme))

4.5.3. 排版 (Typography)

与应用程序中使用的字体相关的样式,包括字体系列、大小、粗细、行高和字母间距。这些样式应至少包含在您的应用程序中一次。根据您的需要,您可能需要使用不同的配置多次包含这些样式。 (例如,如果您的应用程序支持阅读衬线或无衬线字体的内容。)所有组件都有一个排版混合,可用于包含其排版样式。 (例如,@include mat.checkbox-typography($theme))

4.5.4. 密度 (Density)

与应用程序中元素的大小和间距相关的样式。这些样式应至少包含在您的应用程序中一次。根据您的需要,您可能需要使用不同的配置多次包含这些样式。 (例如,如果您的应用程序同时支持正常模式和紧凑模式)。所有组件都有一个密度混合,可用于包含其密度样式。 (例如,@include mat.checkbox-density($theme))

4.5.5. 主题 mixin

所有组件还支持主题 mixin,可用于一次性包含所有主题维度的组件样式。 (例如,@include mat.checkbox-theme($theme))。

推荐的方法是依靠 mixins 来制定基本样式,如果需要,请使用单维 mixins 来覆盖应用程序部分的特定方面(请参阅一个文件中的多个主题 theme 部分。)

4.6. 使用预先构建的主题

Angular Material 包括四个预构建的主题 CSS 文件,每个文件都选择了不同的调色板。如果您不想使用 Sass 定义自定义主题,则可以使用这些预构建主题之一。

主题浅色还是深色?调色板(主要色、强调色、警告色)
deeppurple-amber.css浅色深紫色、琥珀色、红色
indigo-pink.css浅色靛蓝、粉色、红色
pink-bluegrey.css深色粉色、蓝灰色、红色
purple-green.css深色紫色、绿色、红色

这些文件包括库中每个组件的 CSS。要仅包含组件子集的 CSS,您必须使用上面定义主题中详细介绍的 Sass API 。您可以参考这些预构建主题的源代码来查看完整主题定义的示例。

您可以在 Angular Material 的 npm 包 @angular/material/prebuilt-themes 中找到预构建的主题文件。要将预构建的主题包含在您的应用程序中,请将您选择的 CSS 文件添加到项目的 angular.json styles file 数组中。

4.7. 定义多个主题

使用定义主题中描述的 Sass API ,您还可以 通过多次重复 API 调用来定义多个主题。您可以在同一主题文件或单独的主题文件中执行此操作。

4.7.1. 同一个文件中的多个主题

在单个文件中定义多个主题允许您支持多个主题,而无需管理多个 CSS 资源的加载。然而,缺点是您的 CSS 将包含不必要的样式。

为了控制何时应用哪个主题,@includemixins 仅在通过 CSS 规则声明指定的上下文中。有关更多背景信息,请参阅Sass mixin 的文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@use "@angular/material" as mat;

@include mat.core();

// Define a dark theme
$dark-theme: mat.define-dark-theme(
(
color: (
primary: mat.define-palette(mat.$pink-palette),
accent: mat.define-palette(mat.$blue-grey-palette),
),
// Only include `typography` and `density` in the default dark theme.
typography: mat.define-typography-config(),
density: 0,
)
);

// Define a light theme
$light-theme: mat.define-light-theme(
(
color: (
primary: mat.define-palette(mat.$indigo-palette),
accent: mat.define-palette(mat.$pink-palette),
),
)
);

// Apply the dark theme by default
@include mat.core-theme($dark-theme);
@include mat.button-theme($dark-theme);

// Apply the light theme only when the user prefers light themes.
@media (prefers-color-scheme: light) {
// Use the `-color` mixins to only apply color styles without reapplying the same
// typography and density styles.
@include mat.core-color($light-theme);
@include mat.button-color($light-theme);
}

4.7.2. 跨不同文件的多个主题

您可以在单独的文件中定义多个主题,方法是为每个定义主题创建多个主题文件 ,然后将每个文件添加到您的 angular.json styles 中.但是,您必须另外将 每个文件的 inject 选项 设置为 false,以防止同时加载所有主题文件。将此属性设置为 false 时,您的应用程序将负责手动加载所需的文件。此加载的方法取决于您的应用程序。

4.8. 应用背景颜色

默认情况下,Angular Material 不会将任何样式应用于其自身组件之外的 DOM。如果您想设置应用程序的背景颜色以匹配组件的主题,您可以:

  • 如果您正在使用 MatSidenav,您可以将应用程序的主要内容放入其中mat-sidenav-container。或者

  • 将 mat-app-background CSS 类应用到您的主要内容根元素(通常为body)。

4.9. 自定义样式范围

您可以使用 Angular Material 的 Sass mixins 在应用程序的特定范围内自定义组件样式。包含 Sass mixin 的 CSS 规则声明决定了它的范围。下面的示例展示了如何自定义标有.my-special-section CSS 类的元素内所有按钮的颜色。

1
2
3
4
5
6
7
8
9
10
11
@use '@angular/material' as mat;

.my-special-section {
$special-primary: mat.define-palette(mat.$orange-palette);
$special-accent: mat.define-palette(mat.$brown-palette);
$special-theme: mat.define-dark-theme((
color: (primary: $special-primary, accent: $special-accent),
));

@include mat.button-color($special-theme);
}

4.10. 从调色板中读取色调

可以从主题中读取颜色以在您自己的组件中使用。有关这方面的更多信息,请参阅我们的主题化您自己的组件指南

4.11. 定制密度

Angular Material 的密度定制基于 Material Design 密度指南。该系统定义了一个比例,其中零代表默认密度。您可以减少该数字以获得更高的密度,并增加该数字以获得更低的密度。

密度系统基于密度标尺。比例从默认密度 开始0。每个整数步长(-1、-2等)都会将受影响的尺寸减小4px, 直至组件连贯渲染所需的最小尺寸。

出现在基于任务或弹出上下文中的组件(例如MatDatepicker)不会通过密度系统更改其大小。 Material Design 密度指南明确不鼓励增加此类交互的密度,因为它们不会占用应用程序布局中的空间。

您可以将自定义密度设置应用于整个库或使用密度 Sass mixin 的单个组件。

1
2
3
4
5
6
7
8
9
10
11
12
13

// You can set a density setting in your theme to apply to all components.
$dark-theme: mat.define-dark-theme((
color: ...,
typography: ...,
density: -2,
));

// Or you can selectively apply the Sass mixin to affect only specific parts of your application.
.the-dense-zone {
@include mat.button-density(-1);
}

4.12. 强焦点指示

默认情况下,大多数组件通过更改其背景颜色来指示浏览器焦点,如Material Design规范所述。然而,这种行为可能无法满足可访问性要求,例如WCAG,它需要更强的浏览器focus indicators。

Angular Material 支持在聚焦元素上渲染高度可见的轮廓。应用程序可以通过两个 Sass mixin 启用这些强焦点指示器: strong-focus-indicators和strong-focus-indicators-theme。

strong-focus-indicators mixin为所有组件生成结构指示器样式。该 mixin 应该在应用程序中只包含一次,类似于前面描述的core mixin。

strong-focus-indicators-theme mixin仅生成指示器的颜色样式。每个主题应该包含此 mixin 一次,类似于前面描述的主题 mixin。此外,在默认颜色与背景颜色对比不充分的情况下,您可以使用此混合来更改焦点指示器的颜色。

以下示例在应用程序中包含 Strong focus indicators样式以及自定义主题 API 的其余部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

@use '@angular/material' as mat;

@include mat.core();
@include mat.strong-focus-indicators();

$my-primary: mat.define-palette(mat.$indigo-palette, 500);
$my-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);

$my-theme: mat.define-light-theme((
color: (
primary: $my-primary,
accent: $my-accent,
)
));

@include mat.all-component-themes($my-theme);
@include mat.strong-focus-indicators-theme($my-theme);

4.12.1. 定制强焦点指示

您可以传递配置映射来自strong-focus-indicators定义指示器的外观。此配置包括border-style、border-width和border-radius。

您还可以使用 strong-focus-indicators-theme 自定义指示器的颜色。此 mixin 接受主题(如本指南前面所述)或 CSS 颜色值。提供主题时,指示器将使用主调色板的默认色调。

以下示例包括具有自定义设置的强焦点指示器样式以及自定义主题 API 的其余部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

@use '@angular/material' as mat;

@include mat.core();
@include mat.strong-focus-indicators((
border-style: dotted,
border-width: 4px,
border-radius: 2px,
));

$my-primary: mat.define-palette(mat.$indigo-palette, 500);
$my-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);

$my-theme: mat.define-light-theme((
color: (
primary: $my-primary,
accent: $my-accent,
)
));

@include mat.all-component-themes($my-theme);
@include mat.strong-focus-indicators-theme(purple);

4.13. 主题和风格封装

Angular Material 假定默认情况下所有主题样式都作为全局 CSS 加载。如果要在应用程序中使用Shadow DOM,则必须在包含 Angular Material 组件的每个 Shadow root中加载主题样式。您可以通过在每个Shadow root中手动加载 CSS 或使用可构造样式表来实现此目的。

4.14. 用户偏好媒体查询

Angular Material 不会根据用户偏好媒体查询应用样式,例如 prefers-color-scheme或prefers-contrast。相反,Angular Material 的 Sass mixins 使您可以根据对用户最有意义的条件灵活地应用主题样式。这可能意味着直接使用媒体查询或读取保存的用户首选项。

5. Angular 系列文章

最新更新以及更多 Angular 相关文章请访问 Angular 合集 | 鹏叔的技术博客

6. 参考文档

Theming Angular Material

作者

鹏叔

发布于

2024-04-02

更新于

2024-07-10

许可协议

评论