Customizing Ignite UI for Angular Theming
Este artículo lo guiará a través de los detalles de cómo personalizar Ignite UI for Angular y optimizar el tamaño de la hoja de estilo producida. El artículo muestra detalles de cómo funciona la Ignite UI for Angular y presenta su uso avanzado. El artículo es muy útil tanto para realizar una personalización completa de los estilos de los componentes, de modo que su aplicación Angular se adapte a la apariencia deseada, como para hacer que su aplicación sea óptima para la implementación al reducir los tamaños de estilo a solo lo que usa la aplicación.
Note
Este documento describe el sistema de temas en Ignite UI for Angular desde la versión 15 en adelante. Los ejemplos incluyen tanto el uso de las API de Sass proporcionadas por el motor de temas como las variables CSS expuestas.
Getting Started
Usaremos App Builder para producir una aplicación Angular y luego modificaremos su estilo en el repositorio generado. Comenzamos creando una nueva aplicación a partir de la plantilla "Encabezado + mini navegación + contenido + panel lateral" en el App Builder y agregamos algunos componentes a la superficie de diseño.
Luego generamos nuestra aplicación, usando Angular como destino, en un repositorio de GitHub, sobre el cual trabajaremos tanto desde el App Builder como modificando el propio código generado. Después de clonar el repositorio y construir el proyecto, obtenemos la aplicación Angular en ejecución en su estado inicial.
Como puede ver, la aplicación ha aplicado una temática predeterminada, que es la variante material light. El archivo styles.scss
generado tiene este aspecto:
/* You can add global styles to this file, and also import other style files */
// Standard CSS normalize, comment out if not required or using a different module
@use "minireset.css/minireset";
@use "@infragistics/igniteui-angular/theming" as *;
@include core();
@include typography();
@include light-theme($light-material-palette);
body {
background: hsla(var(--ig-surface-500));
color: var(--ig-surface-500-contrast);
}
html, body {
height: 100%;
}
.ig-typography {
h1, h2, h3, h4, h5, h6, p, .ig-typography__body-1 {
margin: 0;
}
}
.outer-wrapper > *:not(router-outlet) {
width: 100%;
}
Theme Customization
Queremos una variante oscura del mismo tema, agregar nuestra propia paleta de colores para que coincida con nuestra marca y cambiar la fuente a Poppins
en lugar de la Titillium Web
predeterminada, todo lo cual podemos cambiar directamente a través del App Builder y podemos impulsar el cambio. como una solicitud de extracción desde App Builder al repositorio.
El styles.scss
actualizado se ve así:
@include core();
@include typography($font-family: "Poppins");
$custom-palette: palette(
$primary: #1028c7,
$secondary: #e0d94c,
$surface: #000,
$gray: #fff
);
@include theme(
$palette: $custom-palette,
$schema: $dark-material-schema
);
Como puede ver, la generación del código cambió del @include light-theme($light-material-palette);
, que es el tema y la paleta de colores predeterminados, a un theme()
incluido, que proporciona como parámetros nuestra paleta de colores personalizada y un esquema de material oscuro para la estructura temática. El resultado de la aplicación Angular en ejecución se ve así ahora:
Queremos profundizar y personalizar un tema de componente específico en nuestra aplicación y lo haremos incorporando las variables CSS para un tema de componente individual, en este caso el tema de la barra de herramientas de cuadrícula.
@include core();
@include typography($font-family: "Poppins");
$primary: #1028c7;
/* All of the components will use this custom color palette */
$custom-palette: palette(
$primary: $primary,
$secondary: #e0d94c,
$surface: #000,
$gray: #fff
);
@include theme(
$palette: $custom-palette,
$schema: $dark-material-schema
);
/* Grid Toolbar */
/* All grid toolbars will have custom background and elevations */
$toolbar-theme: grid-toolbar-theme(
$background-color: $primary
);
@include css-vars($toolbar-theme);
/* END Grid Toolbar */
Y el resultado en nuestra aplicación ahora se ve así:
Se puede aplicar el mismo proceso para anular y personalizar cualquiera de los temas componentes individualmente.
Switching custom themes at runtime
Ahora profundicemos aún más y creemos dos versiones personalizadas del tema, que se pueden cambiar en tiempo de ejecución. Podemos hacer esto con el control/preferencia del usuario y permitirles cambiarlo en cualquier momento. Sin embargo, para el ejemplo, usaremos la preferencia de usuario definida por el sistema operativo (claro u oscuro) para aplicar un tema que coincida con la configuración actual del sistema operativo. Para ello necesitaremos dos paletas de colores:
@use "minireset.css/minireset";
@use "@infragistics/igniteui-angular/theming" as *;
@include core();
@include typography($font-family: "Poppins");
$primary-dark: #1028c7;
$primary-light: #3c55f1;
$secondary-dark: #e0d94c;
$secondary-light: #b4a904;
$custom-palette-dark: palette(
$primary: $primary-dark,
$secondary: $secondary-dark,
$surface: #000,
$gray: #ccc
);
$custom-palette-light: palette(
$primary: $primary-light,
$secondary: $secondary-light,
$surface: #fff,
$gray: #222
);
Luego, nuestra definición de tema irá al alcance general, que usaremos para la variación de luz y crearemos una anulación de paleta en una consulta @media
cuando se detecte la preferencia del sistema operativo del esquema de color oscuro:
@include theme(
$palette: $custom-palette-light,
$schema: $light-material-schema
);
@media (prefers-color-scheme: light) {
/* Grid Toolbar override for light color scheme */
igx-grid-toolbar {
--background-color: #{$primary-light};
--title-text-color: #{text-contrast($primary-light)};
}
/* END Grid Toolbar */
}
@media (prefers-color-scheme: dark) {
// changes native element schema (scrollbars, select, etc.)
:root {
color-scheme: dark;
}
@include palette($custom-palette-dark);
/* Grid Toolbar override for dark color scheme */
igx-grid-toolbar {
--background-color: #{$primary-dark};
--title-text-color: #{text-contrast($primary-dark)};
}
/* END Grid Toolbar */
}
Note
Cambié la anulación del tema igx-grid-toolbar
para anular solo dos de sus variables, en lugar de volver a incluir todas las variables del tema usando css-vars()
. Todas las variables del tema se pueden encontrar en el documento de API de sass correspondiente y son equivalentes a las variables de sass, pero con el prefijo--
en lugar de $
.
Y el resultado ahora se ve así con el tema ligero del sistema operativo:
Y así es como se ve con el tema oscuro del sistema operativo:
Note
El cambio de tiempo de ejecución completo, incluido el cambio preestablecido del esquema de tema Ignite UI, es posible, solo si se crean dos temas completos. En el ejemplo anterior, cambiamos las paletas de colores, pero el esquema del tema sigue siendo $light-material-schema, por lo que no se utilizan todos los tonos correctos de la paleta de colores cuando cambiamos a la paleta de colores oscuros.
What can be customized
La temática Ignite UI abstrae múltiples dimensiones de la tematización y proporciona capacidades de retemática muy sólidas. Los desarrolladores y diseñadores pueden aprovechar las API del motor de temas para crear diseños visuales personalizados para sus aplicaciones, lo que les brinda una apariencia única al usar Ignite UI for Angular. El motor de temas también expone variables de cada una de las dimensiones, que se pueden usar para aplicar temas al resto de la estructura de la aplicación, que no se construye directamente con Ignite UI for Angular como UI. Las dimensiones expuestas para modificaciones son:
- Colors (color palette)
- Shape (borders and radiuses)
- Elevations (shadows)
- Tipografía (fuentes y tamaños de fuente)
- Tamaño (el tamaño de la información que se ajusta en la pantalla)
Note
Si realmente desea un diseño visual totalmente personalizado, deberá modificar todas las dimensiones temáticas admitidas y aprovechará al máximo las API de Sass. Si solo necesita cambiar cosas como las fuentes y algunos colores, puede echar un vistazo a la sección de paletas y tipografía. En la mayoría de los casos, todo lo que necesitará es cambiar algunas variables CSS y no necesitará las API de Sass completas. Hemos hecho esto lo más granular posible, para que se puedan aplicar modificaciones sin resultados secundarios inesperados en el diseño visual de sus aplicaciones.
Theme Optimization
Después de realizar algunas personalizaciones, crearemos la aplicación que generamos y modificamos para ver cómo se ve el tema de nuestra aplicación en términos de tamaño.
Como puede ver, el tema de la aplicación pesa poco más de 400 kb, lo que se reduce a ~40 kb cuando se comprime y transfiere. Esto no es grande, pero ¿puede ser más óptimo? La respuesta es sí, a menos que se utilicen todos los componentes de la suite Ignite UI for Angular. Llamar a @include theme()
trae todos los temas componentes, pero tenemos un mecanismo para decirle a la función qué excluir. Hay un parámetro $exclude
para el mixin de temas, que toma los nombres de los componentes como una matriz y los excluye del tema en el momento de la compilación. Dado que no es tan fácil encontrar y enumerar todos los componentes disponibles en el paquete, es preferible que pueda enumerar todos los componentes que utiliza. Exponemos la lista completa de componentes como una variable, a la que tendrá acceso una vez que
@use "@infragistics/igniteui-angular/theming" as *;
La matriz de componentes se encuentra en $components
y puedes reducir esta lista con los componentes que usas y excluir el resto, como en este ejemplo:
$include: (
igx-navbar,
igx-ripple,
igx-icon,
igx-button,
igx-input-group,
igx-combo,
igx-nav-drawer,
igx-grid,
igx-grid-toolbar
);
@include theme(
$palette: $custom-palette,
$schema: $dark-material-schema,
/* Removing all included components from the full list and excluding the rest */
$exclude: map.keys(map.remove($components, $include...))
);
Note
Algunos temas componentes dependen de otros temas componentes.
Incluso si excluye ciertos temas, la compilación los conservará si utiliza un tema de componente, que depende de un tema excluido.
¿Cómo se ve nuestra compilación después de haber excluido ciertos temas?
Como puede ver, el tamaño de nuestros estilos se reduce a casi la mitad de su tamaño original. Esto parece bastante bueno en este momento, pero ¿podemos reducirlo aún más? De hecho, podemos. La mayor parte del tamaño de los estilos lo toman los componentes más grandes de la suite, en este caso el IgxTreeGridComponent
que tenemos en una de nuestras vistas. Sin embargo, no utilizamos este componente en ninguna otra vista. Podemos hacer que la vista con igx-tree-grid
sea una ruta con carga diferida y podemos incluir el tema de las cuadrículas solo para esa ruta, haciendo así que nuestro CSS de nivel superior sea aún más pequeño. ¿Cómo se hace esto?
Comenzaremos creando un nuevo módulo y un nuevo módulo de enrutamiento en la carpeta con el componente de empleados en nuestra aplicación.
// employees.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { EmployeesRoutingModule } from './employees-routing.module';
import { EmployeesComponent } from './employees.component';
import { IgxButtonModule, IgxComboModule, IgxTreeGridModule } from '@infragistics/igniteui-angular';
@NgModule({
declarations: [
EmployeesComponent
],
imports: [
CommonModule,
EmployeesRoutingModule,
IgxComboModule,
IgxTreeGridModule,
IgxButtonModule
]
})
export class EmployeesModule { }
// employees-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { EmployeesComponent } from './employees.component';
const routes: Routes = [{ path: '', component: EmployeesComponent }];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class EmployeesRoutingModule { }
// Updated top-level app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { PageNotFoundComponent } from './error-routing/not-found/not-found.component';
import { UncaughtErrorComponent } from './error-routing/error/uncaught-error.component';
import { ErrorRoutingModule } from './error-routing/error-routing.module';
import { StatisticsComponent } from './statistics/statistics.component';
export const routes: Routes = [
{ path: '', redirectTo: 'statistics', pathMatch: 'full' },
{ path: 'error', component: UncaughtErrorComponent },
// { path: 'employees', component: EmployeesComponent, data: { text: 'Employees' } },
// lazy-loading the employees route
{ path: 'employees', loadChildren: () => import('./employees/employees.module').then(m => m.EmployeesModule) },
{ path: 'statistics', component: StatisticsComponent, data: { text: 'Statistics' } },
{ path: '**', component: PageNotFoundComponent } // must always be last
];
@NgModule({
imports: [RouterModule.forRoot(routes), ErrorRoutingModule],
exports: [RouterModule, ErrorRoutingModule]
})
export class AppRoutingModule {
}
Ahora eliminamos las importaciones IgxTreeGridModule
e IgxComboModule
, así como EmployeesComponent
de nuestro app.module.ts
porque no usamos las importaciones en ninguna otra vista y solo podemos tener una declaración de componente en todos los módulos.
Luego procederemos eliminando igx-grid
, igx-grid-toolbar
e igx-combo
de nuestro tema incluido, y los incluiremos en el nivel employees.component.scss
.
/* employees.component.scss */
@use "@infragistics/igniteui-angular/theming" as *;
:host ::ng-deep {
height: 100%;
display: flex;
justify-content: flex-start;
align-items: stretch;
align-content: flex-start;
$primary: #1028c7;
@include core();
@include grid(grid-theme());
@include combo(combo-theme());
@include grid-toolbar(
grid-toolbar-theme(
$background-color: $primary,
);
}
/* Updated styles.scss */
@use "sass:map";
@use "minireset.css/minireset";
@use "@infragistics/igniteui-angular/theming" as *;
@include core();
@include typography($font-family: "Poppins");
$primary: #1028c7;
$custom-palette: palette(
$primary: $primary,
$secondary: #e0d94c,
$surface: #000,
$gray: #fff
);
$include: (
igx-navbar,
igx-ripple,
igx-icon,
igx-button,
igx-nav-drawer
);
@include theme(
$palette: $custom-palette,
$schema: $dark-material-schema,
$exclude: map.keys(map.remove($components, $include...),)
);
Note
Probablemente desee colocar todas sus variables, como los valores de la paleta de colores, en un archivo_variables.scss
separado, que puede incluir desde múltiples componentes para reutilizar las variables.
El resultado en términos de construcción es el siguiente:
Como puede ver, nuestro styles.css
de nivel superior se redujo a un poco más de 70 kb, que es un poco menos de 6 kb cuando está comprimido. Comenzamos con ~428kb, ~40kb comprimidos y logramos reducir esto aproximadamente 7 veces en términos de tamaño comprimido. El resto se entrega solo cuando se carga la vista que contiene los componentes igx-tree-grid
e igx-combo
.
Additional Resources
Temas relacionados:
Nuestra comunidad es activa y siempre da la bienvenida a nuevas ideas.