Hoe maak je een aangepast thema in Angular Material

Angular Material is een geweldige bibliotheek die Material Design voor Angular 2+ implementeert. Het officiële document is voldoende met betrekking tot het gebruik van de componenten, terwijl er maar weinig artikelen zijn over het aanpassen van het thema zelf, met name de kleuren die in het thema worden gebruikt.

In dit bericht wil ik samenvatten wat ik deze maanden heb geleerd door het aanpassen van Angular Material-thema's.

Merk op dat dit artikel NIET gaat over AngularJS-materiaal, dat wordt gebruikt voor AngularJS 1.x.

gerelateerde berichten

Enkele veelvoorkomende berichten over het aanpassen van thema's zijn:

  • "Theming your Angular Material-app", de officiële gids voor aangepaste thema's,
  • "De complete gids voor Angular Material Themes" door Tomas Trajan, die veel ongedocumenteerde instructies bevat. Sterk aanbevolen .

Ik heb geen andere nuttige berichten gevonden en zou het op prijs stellen als iemand wat bronnen in de opmerkingen zou kunnen geven.

Hoe u een aangepast thema maakt

Het maken van een materieel thema is uiterst eenvoudig: u hoeft maar drie kleuren te kiezen - primair , accent en waarschuwend - en Angular Material doet de rest voor u. De materiaalpaletpagina legt uit hoe het duidelijk werkt, en u kunt ook visueel een thema maken met Color Tool.

Met betrekking tot code hoeft u alleen maar het volgende themabestand te maken:

// [email protected] '[email protected]/material/theming';
$my-theme-primary: mat-palette($mat-green);$my-theme-accent : mat-palette($mat-amber);$my-theme-warn : mat-palette($mat-red);
$my-theme: mat-light-theme( $my-theme-primary, $my-theme-accent, $my-theme-warn);

Dan moet u dit thema toepassen in uw hoofdbestand style.scss:

@import "theme.scss";
@include mat-core();@include angular-material-theme($my-theme);

Aangepast thema gebruiken in componenten

Nadat we ons eigen thema hebben gemaakt, zullen dit soort vereisten stijgen:

Ik wil een tekstvak maken. De tekstkleur, achtergrondkleur en randkleur moeten allemaal uit ons eigen thema komen, niet door harde codering.

Deze vereiste is vrij gebruikelijk - hoe dan ook, het kunnen worden gebruikt in componenten is precies waarom we een aangepast thema willen maken. Het probleem is hoe.

De mixin benadering

Het eerste officiële document dat ik deelde, stelde een manier voor om de mixin van SCSS te gebruiken. Ik noem het een "bottom-up" -benadering, die de volgende stappen omvat:

  1. Elke component definieert een thema-mixin en haalt kleuren op uit de $themeparameter.
  2. Een globale theme.scssdefinieert het aangepaste thema, bevat vervolgens alle componentthema-mixins en roept ze op met het aangepaste thema.

Naast de theme.scsshierboven genoemde definitie, moet elke component een themabestand als volgt maken:

// src/app/comp-a/[email protected] '[email protected]/material/theming';
@mixin comp-a-theme($theme) { // define mixin $primary: map-get($theme, primary); // retrieve color def button { // apply theme to component background-color: mat-color($primary); }}

En waarschijnlijk wilt u a custom-theme.scssalle thema's op componentniveau importeren:

// src/app/[email protected] '[email protected]/material/theming';@import 'src/app/comp-a/comp-a.theme';@import 'src/app/comp-b/comp-b.theme';
@mixin custom-themes($theme) { @include comp-a-theme($theme); @include comp-b-theme($theme);}

Importeer dan bovenstaande custom-theme.scssin uw theme.scss:

// [email protected] './custom-theme';@include custom-themes($my-theme);

Deze hiërarchie werkt, en is waarschijnlijk de enige manier om meerdere thema's te ondersteunen .

Meestal ondersteunen we echter slechts één thema en het gebruik van een mixin kan omslachtig zijn. Er kleven hoofdzakelijk drie nadelen aan deze aanpak:

  1. Elke kleurreferentie heeft een apart .theme.scssbestand nodig.
  2. custom-theme.scssmoet precies weten welke componenten aangepaste thema's opleveren. Dit creëert onnodige afhankelijkheden.
  3. Het belangrijkste is dat themabestanden op componentniveau niet ingekapseld zijn.

Het eerste en tweede punt spreken voor zich. Laat me een klein beetje uitleggen over punt 3. Dit omvat wat achtergrondkennis genaamd "View Encapsulation".

Angular gebruikt een techniek genaamd "View Encapsulation" om component CSS lokaal te houden. Met andere woorden, regels die voor één component zijn gedefinieerd, blijven in die component en hebben geen invloed op andere componenten.

Op deze manier kunt u de CSS-klassenaam vrij in uw component definiëren zonder dat u zich zorgen hoeft te maken over naamconflicten. View-inkapseling wordt echter alleen gedaan als de CSS is gedefinieerd door middel van @Component, dwz @Component({ styleUrls: ['./comp-a.scss'] }).

Wat betreft ons aangepaste themabestand comp-a.theme.scss, aangezien het rechtstreeks wordt geïmporteerd door custom-theme.scss, zijn de regels niet ingekapseld, dus het is van toepassing op alle elementen op de pagina. In het bovenstaande voorbeeld heb ik de volgende code gebruikt (die VERKEERD was!):

@mixin comp-a-theme($theme) { button { ... } // This will apply to ALL buttons!}

Maar hierdoor wordt de stijl op alle knoppen toegepast in plaats van alleen op de knoppen die bij horen comp-a. U moet zoiets doen comp-a buttonom dit correct te laten werken.

De directe aanpak

Daarom stel ik een betere aanpak voor. In plaats van een mixin te gebruiken, laten we elke component het themabestand opnemen en de kleurdefinitie direct gebruiken.

In deze benadering ziet het componentthema-bestand er als volgt uit:

// NOTE: just do this in your regular scss file.// No need to create separate theme file!// src/app/comp-a/[email protected] 'src/theme.scss';
$primary: map-get($my-theme, primary);button { background-color: mat-color($primary);}

En dat is alles.

Let’s see how this works. First, theme related rules are put into the component SCSS file, so no extra component level theme file required. Second, the main theme.scss does not need to know component level themes (since it does not need to import them), so a simple theme definition is adequate. Third, the component SCSS file is used with @Component so it is encapsulated correctly, which means we can simply define rules for button.

Predefined Theme Keys

Probably you have noticed the next problem. What are the foreground, primary in above theme files ( map-get($my-theme, primary))? Are there any other keys I can use?

Well these “keys” refer to different colors defined in the theme. However I could not find any documents explaining these “keys”, so the only way I could find out is to read the source code. (Although it is said that good programmers should read the code, having to read the code is definitely not a good sign for a library.)

Open node_modules/@angular/material/_theming.scss and you will see the definitions for these keys. For future reference, I would like to summarize the keys here.

$theme |- primary |- accent |- warn |- foreground | |- base | |- divider | |- dividers | |- disabled | |- disabled-button | |- disabled-text | |- hint-text | |- secondary-text | |- icon | |- icons | |- text | |- slider-min | |- slider-off | `- slider-off-active |- background | |- status-bar | |- app-bar | |- background | |- hover | |- card | |- dialog | |- disabled-button | |- raised-button | |- focused-button | |- selected-button | |- selected-disabled-button | |- disabled-button-toggle | |- unselected-chip | `- disabled-list-option `- is-dark // bool, whether dark theme or not

For example, if you want to render a disabled text in your component, you may want to use the following code:

$foreground: map-get($my-theme, foreground);.disabled-text { color: mat-color($foreground, disabled-text);}

Okay these are some lessons I’ve learned from struggling with Angular Material. Hope this post is helpful if you are facing similar problems.