为你自己的组件设置主题 Theming your own components

Theme your own components with Angular Material's theming system

You can use Angular Material's Sass-based theming system for your own custom components.

As described in the theming guide, a theme is a Sass map that contains style values to customize components. Angular Material provides APIs for reading values from this data structure.

To read color values from a theme, you can use the get-color-config Sass function. This function returns a Sass map containing the theme's primary, accent, and warn palettes, as well as a flag indicating whether dark mode is set.

@use 'sass:map';
@use '[email protected]/material' as mat;

$color-config:    mat.get-color-config($theme);
$primary-palette: map.get($color-config, 'primary');
$accent-palette:  map.get($color-config, 'accent');
$warn-palette:    map.get($color-config, 'warn');
$is-dark-theme:   map.get($color-config, 'is-dark');

See the theming guide for more information on reading hues from palettes.

To read typography values from a theme, you can use the get-typography-config Sass function. See the Typography guide for more information about the typography config data structure and for APIs for reading values from this config.

@use '[email protected]/material' as mat;

$typography-config: mat.get-typography-config($theme);
$my-font-family: mat.font-family($typography-config);

Angular Material components each have a Sass file that defines mixins for customizing that component's color and typography. For example, MatButton has mixins for button-color and button-typography. Each mixin emits all color and typography styles for that component, respectively.

You can mirror this structure in your components by defining your own mixins. These mixins should accept an Angular Material theme, from which they can read color and typography values. You can then include these mixins in your application along with Angular Material's own mixins.

To illustrate participation in Angular Material's theming system, we can look at an example of a custom carousel component. The carousel starts with a single file, carousel.scss, that contains structural, color, and typography styles. This file is included in the styleUrls of the component.

// carousel.scss

.my-carousel {
  display: flex;
  font-family: serif;
}

.my-carousel-button {
  border-radius: 50%;
  color: blue;
}

To change this file to participate in Angular Material's theming system, we split the styles into two files, with the color and typography styles moved into mixins. By convention, the new file name ends with -theme. Additionally, the file starts with an underscore (_), indicating that this is a Sass partial file. See the Sass documentation for more information about partial files.

// carousel.scss

.my-carousel {
  display: flex;
}

.my-carousel-button {
  border-radius: 50%;
}
// _carousel-theme.scss

@mixin color($theme) {
  .my-carousel-button {
    color: blue;
  }
}

@mixin typography($theme) {
  .my-carousel {
    font-family: serif;
  }
}

Now that theme theme-based styles reside in mixins, we can extract the values we need from the theme passed into the mixins.

// _carousel-theme.scss

@use 'sass:map';
@use '[email protected]/material' as mat;

@mixin color($theme) {
  // Get the color config from the theme.
  $color-config: mat.get-color-config($theme);

  // Get the primary color palette from the color-config.
  $primary-palette: map.get($color-config, 'primary');

  .my-carousel-button {
    // Read the 500 hue from the primary color palette.
    color: mat.get-color-from-palette($primary-palette, 500);
  }
}

@mixin typography($theme) {
  // Get the typography config from the theme.
  $typography-config: mat.get-typography-config($theme);

  .my-carousel {
    font-family: mat.font-family($typography-config);
  }
}

For convenience, we can add a theme mixin that includes both color and typography. This theme mixin should only emit the styles for each color and typography, respectively, if they have a config specified.

// _carousel-theme.scss

@use 'sass:map';
@use '[email protected]/material' as mat;

@mixin color($theme) {
  // Get the color config from the theme.
  $color-config: mat.get-color-config($theme);

  // Get the primary color palette from the color-config.
  $primary-palette: map.get($color-config, 'primary');

  .my-carousel-button {
    // Read the 500 hue from the primary color palette.
    color: mat.get-color-from-palette($primary-palette, 500);
  }
}

@mixin typography($theme) {
  // Get the typography config from the theme.
  $typography-config: mat.get-typography-config($theme);

  .my-carousel {
    font-family: mat.font-family($typography-config);
  }
}

@mixin theme($theme) {
  $color-config: mat.get-color-config($theme);
  @if $color-config != null {
    @include color($theme);
  }

  $typography-config: mat.get-typography-config($theme);
  @if $typography-config != null {
    @include typography($theme);
  }
}

Now that you've defined the carousel component's theme mixin, you can include this mixin along with the other theme mixins in your application.

@use '[email protected]/material' as mat;
@use './path/to/carousel-theme' as carousel;

@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(
    $font-family: serif,
  );
));

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