Tabla de Contenidos
9. Angular: Personalizando Material (Tokens)
Los componentes de Angular Material se personalizan con tokens, que no son más que variables CSS. Hay dos tipos:
- Design Tokens: Las variables de cada componente, por ejemplo
--mat-button-filled-container-colores el color de fondo de un botónfilled. Se modifican con losmixins*-overridesde cada componente. - System Tokens: Las variables globales que afectan a todos los componentes, por ejemplo
--mat-sys-primaryes el color principal. Se modifican con el tema.
Si no cambiamos un Design Token, su valor es el de un System Token. Por eso cambiando el tema cambian todos los componentes a la vez.
Design Tokens
En la documentación del componente Button está la pestaña de styling que contiene una descripción de todos los Tokens de diseño que podemos modificar.
Para el componente Button, los tokens están agrupados en estos 3 grupos (realmente están agrupados en mixins de SASS):
fab-overrides: Para los botones que solo son iconos y parecen que estén como flotando sobre la página por eso se llaman Floating Action Button (FAB)icon-button-overrides: Para los iconos de los botonesbutton-overrides: Para cada botón.
Para cada grupo (mixin) hay una serie de tokens de diseño. Vamos a ver algún ejemplo con button-overrides:
filled-label-text-size: El tamaño de fuente para botonesfilled.outlined-label-text-size: El tamaño de fuente para botonesoutlined.
¿Como cambiamos entonces esos valores? Pues creamos una clase CSS en SASS con lo siguiente:
@use '@angular/material' as mat;
.botones-grandes {
@include mat.button-overrides((
filled-label-text-size: 20px,
outlined-label-text-size: 20px
));
}
Si queremos que sea para todos los componentes no hay más que hacer:
@use '@angular/material' as mat;
html {
@include mat.button-overrides((
filled-label-text-size: 20px,
outlined-label-text-size: 20px
));
}
Actualmente en Angular Material 20, todos esos Tokens de diseño realmente se transforman en variables CSS
Veamos algunos ejemplos:
- Para botones
filledfilled-container-color: Color del fondofilled-label-text-color: Color del textofilled-container-shape: Es elborder-radiusfilled-horizontal-padding: El padding horizontalfilled-label-text-size: Tamaño de fuente
- Para botones
outlinedoutlined-label-text-color: Color del textooutlined-outline-color: Color del bordeoutlined-state-layer-color: Color del fondo al hacer "hover"outlined-container-shape: Es elborder-radiusoutlined-horizontal-padding: El padding horizontaloutlined-label-text-size: Tamaño de fuente
- Para botones
texttext-label-text-color: Color del textotext-state-layer-color: Color del fondo al hacer "hover"text-container-shape: Es elborder-radiustext-horizontal-padding: El padding horizontaltext-label-text-size: Tamaño de fuente
Propiedades CSS
- Para botones
filled--mat-button-filled-container-color--mat-button-filled-label-text-color--mat-button-filled-container-shape--mat-button-filled-horizontal-padding--mat-button-filled-label-text-size
- Para botones
outlined--mat-button-outlined-label-text-color--mat-button-outlined-outline-color--mat-button-outlined-state-layer-color--mat-button-outlined-container-shape--mat-button-outlined-horizontal-padding--mat-button-outlined-label-text-size
- Para botones
text--mat-button-text-label-text-color--mat-button-text-state-layer-color--mat-button-text-container-shape--mat-button-text-horizontal-padding--mat-button-text-label-text-size
System Tokens
Resulta que si vemos el código CSS que usa Angular Material para los Design Tokens, podemos comprobar que es de la siguiente forma:
background-color: var(--mat-button-filled-container-color, var(--mat-sys-primary));
color: var(--mat-button-filled-label-text-color, var(--mat-sys-on-primary));
border-radius:var(--mat-button-filled-container-shape, var(--mat-sys-corner-full));
padding: 0 var(--mat-button-filled-horizontal-padding, 24px);
font-size: var(--mat-button-filled-label-text-size, var(--mat-sys-label-large-size));
color: var(--mat-button-outlined-label-text-color, var(--mat-sys-primary));
border-color: var(--mat-button-outlined-outline-color, var(--mat-sys-outline));
background-color:var(--mat-button-outlined-state-layer-color, var(--mat-sys-primary));
border-radius: var(--mat-button-outlined-container-shape, var(--mat-sys-corner-full));
padding: 0 var(--mat-button-outlined-horizontal-padding, 24px);
font-size: var(--mat-button-outlined-label-text-size, var(--mat-sys-label-large-size));
color: var(--mat-button-text-label-text-color, var(--mat-sys-primary));
background-color:var(--mat-button-text-state-layer-color, var(--mat-sys-primary));
border-radius:var(--mat-button-text-container-shape, var(--mat-sys-corner-full));
padding: 0 var(--mat-button-text-horizontal-padding, 12px);
font-size: var(--mat-button-text-label-text-size, var(--mat-sys-label-large-size));
Es decir que hay una serie de variable CSS globales que afectan a todo Angular Material. Esas variables CSS globales se llaman System Tokens. Y que como vemos empieza por --mat-sys:
--mat-sys-primary--mat-sys-on-primary--mat-sys-corner-full--mat-sys-outline--mat-sys-label-large-size
¿Como podemos saber el listado completo de variables globales (System Tokens)? Creando una paleta nueva Custom Color Palettes mediante ng generate @angular/material:theme-color pero indicando que la queremos CSS y no SASS
logongas@beren:~/Documentos/ensenyament/2daw-diw/EjemploComponentesAngular$ ng generate @angular/material:theme-color ✔ What HEX color should be used to generate the M3 theme? It will represent your primary color palette. (ex. #ffffff) #1979E6 ✔ What HEX color should be used represent the secondary color palette? (Leave blank to use generated colors from Material) #E67519 ✔ What HEX color should be used represent the tertiary color palette? (Leave blank to use generated colors from Material) ✔ What HEX color should be used represent the neutral color palette? (Leave blank to use generated colors from Material) ✔ What HEX color should be used represent the neutral variant palette? (Leave blank to use generated colors from Material) ✔ What HEX color should be used represent the error palette? (Leave blank to use generated colors from Material) ✔ Do you want to generate high contrast value override mixins for your themes?. Providing a high contrast version of your theme when a user specifies helps increase the accesibility of your application. No ✔ What is the directory you want to place the generated theme file in? (Enter the relative path such as 'src/app/styles/' or leave blank to generate at your project root) src/app/styles/variables_material.css ✔ Do you want the generated file to be a scss file? This is the recommended way of setting up theming in your application. If not, a CSS file will be generated with all the system variables defined. (Leave blank to generate a scss file) No CREATE src/app/styles/variables_material.csstheme.css (13578 bytes)
Y generará un fichero CSS con todas las variables (System Tokens) , un ejemplo es este fichero: variables_material.csstheme.css
Temas
Para modificar los System Tokens no deberíamos modificar directamente las variables de ese fichero sino crear un tema con el mixin mat.theme.
Al añadir Angular Material se añade el siguiente código en styles.scss
@use '@angular/material' as mat;
html {
@include mat.theme((
color: (
primary: mat.$azure-palette,
tertiary: mat.$blue-palette
),
typography: Roboto,
density: 0,
));
}
Pues si queremos definir algún System Tokens no tenemos que añadir más que un map con los System Tokens y sus nuevos valores
@use '@angular/material' as mat;
html {
@include mat.theme((
color: (
primary: mat.$azure-palette,
tertiary: mat.$blue-palette
),
typography: Roboto,
density: 0,
),(
corner-full:6px,
label-large-size: 30px
));
}
Vemos en el ejemplo que ahora el border-radius sería de 6px al haber cambiado el valor del System Token corner-full,
mientras que el tipo de letra grande ahora sería de 30px al haber definido el System Token de label-large-size
Paletas de colores
Para terminar nuestra personalización de Angular Material, nos hace falta definir los colores.
En Angular Material hay 5 tipos de colores pero los importantes son:
primary: El color principalsecondary: Otro color para diferenciarse un poco del primario pero que no destaca , se usa para que todo no tenga el mismo color y no sea todo tan uniformetertiary: Es el color que queremos que destaque sobre el primario.
Para generar nuestra paleta de colores tenemos que volver a usar el comando ng generate @angular/material:theme-color pero esta vez si que le diremos que sea SASS y definiremos los colores que queremos.
ng generate @angular/material:theme-color ✔ What HEX color should be used to generate the M3 theme? It will represent your primary color palette. (ex. #ffffff) #4084BF ✔ What HEX color should be used represent the secondary color palette? (Leave blank to use generated colors from Material) #B5BF40 ✔ What HEX color should be used represent the tertiary color palette? (Leave blank to use generated colors from Material) #BF4040 ✔ What HEX color should be used represent the neutral color palette? (Leave blank to use generated colors from Material) ✔ What HEX color should be used represent the neutral variant palette? (Leave blank to use generated colors from Material) ✔ What HEX color should be used represent the error palette? (Leave blank to use generated colors from Material) ✔ Do you want to generate high contrast value override mixins for your themes?. Providing a high contrast version of your theme when a user specifies helps increase the accesibility of your application. No ✔ What is the directory you want to place the generated theme file in? (Enter the relative path such as 'src/app/styles/' or leave blank to generate at your project root) src/app/styles/ ✔ Do you want the generated file to be a scss file? This is the recommended way of setting up theming in your application. If not, a CSS file will be generated with all the system variables defined. (Leave blank to generate a scss file) Yes CREATE src/app/styles/_theme-colors.scss (2555 bytes)
En el ejemplo se ha creado el fichero _theme-colors.scss
// This file was generated by running 'ng generate @angular/material:theme-color'. // Proceed with caution if making changes to this file. @use 'sass:map'; @use '@angular/material' as mat; // Note: Color palettes are generated from primary: #4084BF, secondary: #B5BF40, tertiary: #BF4040, neutral: #74808B, neutral variant: #B7C5D2, error: #BE4141 $_palettes: ( primary: (0: #000000,10: #001d34,20: #003355,25: #003e66,30: #004a78,35: #00568b,40: #0d629b,50: #367bb6,60: #5495d2,70: #70b0ee,80: #99cbff,90: #cfe5ff,95: #e8f1ff,98: #f7f9ff,99: #fcfcff,100: #ffffff), secondary: (0: #000000,10: #1b1d00,20: #2f3300,25: #3a3f00,30: #454a00,35: #515700,40: #5c6300,50: #757d00,60: #8e9718,70: #a9b334,80: #c4ce4e,90: #e0eb67,95: #effa74,98: #faffb0,99: #feffd6,100: #ffffff), tertiary: (0: #000000,10: #410005,20: #68000d,25: #7a0a15,30: #8b191f,35: #9b2629,40: #ac3233,50: #cd4a49,60: #ef6360,70: #ff8984,80: #ffb3af,90: #ffdad7,95: #ffedeb,98: #fff8f7,99: #fffbff,100: #ffffff), neutral: (0: #000000,10: #111d26,20: #26323b,25: #313d46,30: #3c4852,35: #48545e,40: #54606a,50: #6d7883,60: #86929d,70: #a0adb8,80: #bcc8d4,90: #d8e4f0,95: #e6f2ff,98: #f6faff,99: #fcfcff,100: #ffffff,4: #040f18,6: #09151d,12: #15212a,17: #202b34,22: #2b3640,24: #2f3b44,87: #cfdbe8,92: #ddeaf6,94: #e3effc,96: #ebf5ff), neutral-variant: (0: #000000,10: #101d27,20: #25323c,25: #303d47,30: #3b4853,35: #47545f,40: #53606b,50: #6b7984,60: #85929f,70: #9fadba,80: #bac8d5,90: #d6e4f2,95: #e5f2ff,98: #f6faff,99: #fcfcff,100: #ffffff), error: (0: #000000,10: #410005,20: #68000d,25: #790c16,30: #8a1a20,35: #9a272a,40: #ab3334,50: #cc4b4a,60: #ee6462,70: #ff8984,80: #ffb3af,90: #ffdad7,95: #ffedeb,98: #fff8f7,99: #fffbff,100: #ffffff), ); $_rest: ( secondary: map.get($_palettes, secondary), neutral: map.get($_palettes, neutral), neutral-variant: map.get($_palettes, neutral-variant), error: map.get($_palettes, error), ); $primary-palette: map.merge(map.get($_palettes, primary), $_rest); $tertiary-palette: map.merge(map.get($_palettes, tertiary), $_rest);
Este fichero crea las variables SASS con las paletas de colores.
$primary-palette$tertiary-palette
Cada paleta (variable de SASS) ya incluye además los colores secondary, neutral, neutral-variant y error.
Y ahora ya podemos usarlos para crear nuestro tema con nuestros colores y nuestros System Tokens. Hay que cargar con @use el fichero generado:
@use '@angular/material' as mat;
@use './app/styles/theme-colors' as colores;
html {
@include mat.theme((
color: (
primary: colores.$primary-palette,
tertiary: colores.$tertiary-palette
),
typography: Roboto,
density: 0,
),(
corner-full:6px,
label-large-size: 30px
));
}
El ejemplo completo con todo el código se puede ver en GitHub en https://github.com/lgonzalezmislata/personalizar-angular-material
Más información
- Customizing Angular Material Buttons with Design Tokens - Part 1: Personalizar los colores de los botones
- Can Angular Material Buttons Really Look Like shadcn? (Part 2): Personalizar la forma de los botones
- Angular Customizable Dashboard with Material 3: Lista de reproducción
