Son capas independientes pero permeables, con su propia cascada y lógica de especificidad, que se apilan unas sobre otras, lo que nos permite mantener nuestro código más estructurado, ordenado y fácil de localizar.
Es como si dividiésemos nuestro CSS en diferentes hojas de estilo y las incluyésemos en el documento una a continuación de la anterior con la etiqueta [.rr-code]<link>[.rr-code] o [.rr-code]<style>[.rr-code], pero con un funcionamiento diferente por las reglas de especificidad propias de las capas.
En realidad, ya trabajamos con el concepto de capas como estilos que se apilan, puesto que los estilos que los desarrolladores (autores) creamos, además de las preferencias del usuario, se aplican encima de los estilos que los navegadores dan a las etiquetas HTML.
Pero con Cascade Layers vamos a tener un control más fino, flexible y granular ya que podremos organizarlos en orden de importancia, de manera que los estilos más específicos tengan prioridad sobre los estilos más generales.
Qué problemas resuelven
- Organización de los estilos según abstracciones representativas.
- Facilita sobrescribir estilos.
Al poder separar nuestros estilos en capas podemos organizarlos mejor, de forma más intuitiva y con un control más fino. Además, nos facilita la tarea del viejo y conocido problema de sobrescribir estilos lidiando con la especificidad, por lo que es una solución perfecta para trabajar en grandes proyectos.
Qué problemas persisten
- La encapsulación nativa de estilos
Las capas son permeables, no hay encapsulación y, por lo tanto, unas pueden sobrescribir a otras, lo que nos puede llevar a obtener resultados no deseados si dejamos de prestar atención a la hora de escribir nuestras clases. Es por eso que BEM (por poner un ejemplo de nomenclatura) sigue siendo un enfoque muy útil para evitar colisiones.
La encapsulación de estilos por componentes está resuelta, por ejemplo, cuando utilizamos frameworks de desarrollo que traen consigo CSS modules o CSS-in-JS, pero estas soluciones pueden llevarnos a un exceso de confianza y a repetir nombres de clases en diferentes componentes. Por lo tanto, hay que recordar que al no existir (todavía) encapsulación nativa de CSS (salvo que usemos web components), debemos siempre prestar atención al escribir nuestras clases y elegir una metodología común para el equipo.
Cómo trabajar con capas
Creando las capas
Las capas se declaran creando un nuevo bloque de estilos utilizando la directiva [.rr-code]@layer[.rr-code] y pueden ser anónimas o tener nombre.
Ordenando las capas
Una vez creadas las capas, el orden de aparición es importante, ya que la última capa tiene mayor relevancia y sobrescribirá a la anterior. Hasta ahora, es el funcionamiento esperado ya que es como se comporta CSS.
En el ejemplo anterior, [.rr-code].rectangle[.rr-code] será de color [.rr-code]lime[.rr-code]. Sin embargo, el orden de apilamiento puede ser alterado si lo declaramos utilizando [.rr-code]@layer[.rr-code] seguido (y separado por comas) de los nombres de las capas creadas, siendo la primera la de menor relevancia y la última la de mayor. Es conveniente que esta declaración se produzca al principio del documento.
En este caso, [.rr-code].rectangle[.rr-code] seguirá siendo [.rr-code]lime[.rr-code] porque al ordenarlas [.rr-code]theme[.rr-code] ha sido declarada después que [.rr-code]default[.rr-code]. De esta manera, podemos controlar el estilado final reordenando las capas sin tener que confiar en el orden en el que fueron escritas.
Fusionando capas
Los nombres de las capas pueden repetirse, pero hay que tener en cuenta que el navegador las fusionará entre sí para formar una única capa.
Así en el ejemplo anterior, [.rr-code].rectangle[.rr-code] será de color [.rr-code]coral[.rr-code] y tendrá un borde de un [.rr-code]1px[.rr-code].
Anidando capas
Las capas se pueden anidar, por lo tanto podemos establecer relaciones lógicas y semánticas entre ellas, y referenciarlas para modificarlas o extenderlas más adelante.
Importando ficheros externos a capas
Una funcionalidad muy interesante es la de poder envolver ficheros enteros en capas para poder organizarlas mejor. Podríamos por ejemplo, envolver librerías de terceros y declararlas con una relevancia media o baja para que las próximas capas puedan sobrescribir sus estilos fácilmente, siempre que no contengan [.rr-code]!important[.rr-code].
Importando CSS externo usando [.rr-code]<link>[.rr-code]
Actualmente no se puede envolver un archivo en una capa usando la etiqueta [.rr-code]<link>[.rr-code], sin embargo ya existe una propuesta formal de Miriam Suzanne para que se incluya como funcionalidad. En este momento la importación se hace usando [.rr-code]@import[.rr-code] pero estas regla es bloqueante, ya que mientras se resuelve la petición la carga de la página queda bloqueada, mientras que [.rr-code]<link>[.rr-code] no bloquea la lectura del código por el navegador.
Cómo se relacionan las capas con el resto de estilos
Los estilos que renderiza el navegador son el resultado de su proceso interno de ordenamiento según su relevancia, lo que llamamos cascada.
La cascada toma una lista desordenada de valores declarados para una propiedad de un elemento concreto, los ordena según su precedencia y devuelve un único valor. - W3C
Los navegadores siguen este esquema (simplificado) para determinar la cascada:
- Origen e importancia (a. Estilos del navegador, b. Preferencias del usuario, c. Estilos del autor (desarrollador) - Estilos con [.rr-code]!important[.rr-code])
- Contexto
- Estilos declarados mediante el atributo [.rr-code]style[.rr-code]
- Capas
- Especificidad de los selectores
- Orden de aparición en el código
La especificidad en las capas
Dentro de una capa, la especificidad funciona tal y como estamos acostumbrados. Los selectores más específicos van a sobrescribir a los menos específicos.
Si dudas de la especificidad de los selectores, echa un vistazo a esta calculadora.
Sin embargo, si usamos cascade layers no importa cómo de específico sea un selector si en alguna capa posterior se le aplican estilos diferentes, aunque sea con un selector menos específico.
En este ejemplo, a pesar de que el selector de la capa [.rr-code]theme[.rr-code] tiene un peso (1, 1, 1) y el de la capa [.rr-code]overrides[.rr-code] sólo (0, 0 , 1) el color de fondo será [.rr-code]coral[.rr-code] porque la capa [.rr-code]overrides[.rr-code] está declarada después 🤯.
Una vez que se evalúan las capas y una es la “ganadora” no se continua evaluando la especificidad o el orden de aparición para el resto de las capas, así que no necesitarás volver a preocuparte si un selector se repite en diferentes capas y tiene diferente especificidad.
Estilos declarados fuera de una capa
Por otro lado, un factor a tener en cuenta es que las capas tienen menor relevancia que los estilos declarados fuera de ellas, aunque estén escritos antes que las capas, y es porque los estilos fuera de las capas se interpretan como parte de una última capa final, y por eso prevalecen.
En el ejemplo anterior, el color de fondo de [.rr-code]section[.rr-code] es [.rr-code]aqua[.rr-code] a pesar de lo poco específico de su selector e incluso de estar declarado antes que las capas.
!important
Por último, hay que tener en cuenta que una capa con menor relevancia pero que contenga un valor para una propiedad con [.rr-code]!important[.rr-code] prevalecerá. Es decir, tendrá más peso que una capa más relevante, anulando el funcionamiento que hemos descrito hasta ahora.
Así que, la primera capa (y menos relevante) con un [.rr-code]!important[.rr-code] sobrescribirá capas posteriores, no importa si en ellas también se utiliza [.rr-code]!important[.rr-code] para intentar sobrescribir la capa anterior. Dado este comportamiento, una idea interesante es la declarar aquellos valores que no queremos que sean sobrescritos lo más próximo al inicio del documento.
En el ejemplo anterior, el color de fondo de section será [.rr-code]lime[.rr-code].
Soporte
De acuerdo a caniuse, el soporte es casi total, así que podemos utilizarlo sin problema.
Cómo usarlo en proyectos reales
Cascade Layers encaja perfectamente en cualquier tipo de proyecto, y no necesariamente tiene que ser un proyecto exclusivo con este enfoque, puedes añadir alguna capa a tu proyecto con CSS habitual, pero puede ser especialmente adecuado para tareas concretas como:
- Escribir hojas de estilo tipo reset o estilos base de la aplicación
- Sobrescribir librerías frameworks de CSS o librerías de terceros
- Agrupar estilos por componentes
- Aplicar temificados
- Crear modo oscuro y modo claro
- Agrupar estilos para los estados de algunos elementos
Conclusión
Aunque no resuelve la encapsulación, es una herramienta muy útil para gestionar los estilos de tus aplicaciones.
Sin embargo, hay ciertas reglas sobre la revelancia de las capas que hay que tener en mente para evitar resultados inesperados, ya que al principio puede costar el cambio de mentalidad y depurar los estilos cuando existen capas anidadas.
Enlaces de interés
- Especificación
- Soporte en caniuse
- Artículo en developer.chrome
- Artículo en bram.us
- Artículo en smashing magazine
* La imagen del artículo es una foto de Clark Van Der Beken en Unsplash.