Si bien al escribir nuestras hojas de estilos podemos ayudarnos de herramientas como Stylelint y a la hora de llevar a producción nuestro proyecto de Angular activamos la opción de optimización, siempre podemos mejorar un poco más el resultado de la optimización gracias a la librería cssnano. No lo dudes, optimiza el CSS con cssnano.
La librería cssnano obtiene tu CSS bien formateado y lo ejecuta a través de muchas optimizaciones específicas, para garantizar que el resultado final sea lo más pequeño posible para un entorno de producción. Además, admite configuraciones personalizadas mediante ajustes preestablecidos que controlan el nivel de optimización que desees. Tecnológicamente, cssnano funciona con PostCSS, una herramienta para transformar estilos con JavaScript. Específicamente, su arquitectura de complementos nos permite componer cssnano a partir de pequeños módulos con responsabilidades limitadas. También le permite insertar fácilmente cssnano en su paso de compilación, junto con otros procesadores que pueden detectar errores en su CSS o transpilar sintaxis futura.
Ajustes preestablecidos
Como se ha comentado anteriormente, dispone de tres «presets» de optimizaciones para que solamente tengas que seleccionarlo sin necesidad de especificar cada regla:
- Preset lite: Conjunto de reglas muy reducido, no optimizará mucho pero es un punto de partida.
- Preset default: Reglas estándar para la optimización. Con este preset hay más que suficiente para mejorar de saque el css.
- Preset advanced: Añade más reglas de optimización que potencian más la optimización pero por contrapartida hay que validar si el CSS resultante es correcto.
Aquí te dejo el cuadro de presets con sus respectivas reglas activadas. Con el preset default hay más que suficiente para mejorar el css final.
Te invito a que visualices algunas optimizaciones:
- mergeRules: Combina la repetición de selectores en uno. Esto ahorra la repetición del selector en el CSS final
- normalizeUrl: Optimiza las cadenas de URL. Puede ahorrar diretorios innecesarios, comillas, …
- discardDuplicates: Elimina duplicidades.
- colormin: Convierte la definición de un color a su expresión mínima.
- …
Utilizando cssnano en Angular
Si ya tienes tu proyecto de Angular creado, hay que instalar la librería al package.json de la siguiente manera:
npm install --save-dev cssnano
Normalmente en el proyecto de Angular ya viene instalada la librería postcss. Si estás en otro tipo de proyecto deberías instalar también postCSS.
Ahora solo hace falta añadir un archivo de configuración de postCSS en la raíz del proyecto (donde esté ubicado el angular.json) seleccionando el preset que más nos convenga. En el ejemplo tomaremos el preset default.
El nombre del archivo de configuración debe llamarse «postcss.config.json» ó «.postcssrc.json» (lo dejo a tu elección). y el contenido debería ser el siguiente (dependiendo de si ya tenías una configuración previa de postcss):
{
"plugins": {
"cssnano": {
"preset": "default"
}
}
}
Ahora ya, cada vez que realices el build se ejecutará automáticamente el proceso de optimización con cssnano. Puedes comprobar el antes y el después de la optimización (sobre todo comparar el espacio que ocupa el archivo css) así como si funciona correctamente. Naturalmente puedes modificar la configuración de cssnano activando o desactivando reglas de optimización.
Resultados
Partimos de dos archivos de estilos en formato scss:
Archivo «_functions.scss:
.flex {
display:flex;
}
.horizontal-list {
flex-wrap: wrap;
justify-content: space-between;
list-style: none;
padding: 0;
margin: 0;
li {
margin-bottom: 1rem;
}
}
.vertical-list {
display: flex;
flex-direction: column;
list-style: none;
padding: 0;
margin: 0;
li {
margin-bottom: 1rem;
}
}
Archivo «styles.scss»:
@use "functions" as *;
.include {
/*test*/
@extend .flex;
@extend .horizontal-list;
}
.block {
padding-right:5px;
padding-left:5px;
padding-top: 0px;
padding-bottom: 0px;
}
.block {
padding-left:5px;
}
.empty {}
.example {
display: grid;
transition: all .5s;
user-select: none;
background: linear-gradient(to bottom, white, black);
}
Ahora, si realizamos el build en modo producción, sin la optimización obtenemos el siguiente resultado:

El contenido del archivo css resultante es el siguiente:
.flex,.include{display:flex}.horizontal-list,.include{flex-wrap:wrap;justify-content:space-between;list-style:none;padding:0;margin:0}.horizontal-list li,.include li{margin-bottom:1rem}.vertical-list{display:flex;flex-direction:column;list-style:none;padding:0;margin:0}.vertical-list li{margin-bottom:1rem}.block{padding:0 5px}.block{padding-left:5px}.example{display:grid;transition:all .5s;user-select:none;background:linear-gradient(to bottom,#fff,#000)}
Con la optimización obtenemos el siguiente resultado:

El contenido del archivo css resultante es el siguiente:
.flex,.include{display:flex}.horizontal-list,.include{flex-wrap:wrap;justify-content:space-between;list-style:none;margin:0;padding:0}.horizontal-list li,.include li{margin-bottom:1rem}.vertical-list{display:flex;flex-direction:column;list-style:none;margin:0;padding:0}.vertical-list li{margin-bottom:1rem}.block{padding:0 5px}.example{background:linear-gradient(180deg,#fff,#000);display:grid;transition:all .5s;user-select:none}
Vemos que algo sí ha mejorado, hemos pasado de 459 bytes a 432 bytes, es decir, un ahorro de 27 bytes con este ejemplo sencillo. No obstante en un proyecto grande donde hay muchísimos más hojas de estilos el ahorro puede ser mucho mayor.
En nuestro caso concreto, ha optimizado la clase «.block» que estaba repetida (24 bytes) así como el estilo «.example» con el linear-gradient (3 bytes).
Por contra el proceso de build se alarga un poco más al ejecutar este paso, en el ejemplo hemos pasado de unos 5.075 segundos a 5.612, es decir, el proceso se ha alargado medio segundo (en cada proceso se ha ejecutado en la misma máquina eliminando la cache «.angular» y «dist»).