La regla @layer
de CSS permite declarar las llamadas capas de cascada. Este concepto es muy similar a las capas de un editor gráfico como Photoshop, GIMP o Inkscape: crean diferentes grupos, sólo que en nuestro caso en lugar de colocar imágenes en cada grupo, colocamos código CSS.
¿Cuál es la finalidad de las capas de cascada? Organizar mejor nuestro código, evitar los clásicos problemas de especificidad CSS y reducir la necesidad de utilizar !important
o reescribir los selectores CSS:
@layer nombre {
/* Reglas CSS */
}
¿Cuál es su finalidad? ¿Para qué necesitamos las capas? Básicamente para poder reordenarlas y evitar problemas de especificidad que pueden aparecer a la larga. Lo explicaremos a lo largo de este artículo.
Crear capas en CSS
Primero, vamos a conocer las múltiples formas de crear capas en CSS utilizando la regla @layer
, o incluso mediante la regla @import
que vimos en algún tema anterior. Luego, cuando tengamos eso claro, explicaremos como funcionan.
Las sintaxis que tenemos disponibles son las siguientes:
Formato | Descripción |
---|---|
@layer nombre | Crea una capa CSS con el nombre indicado. |
@layer | Crea una capa CSS anónima (sin nombre). |
@layer nombre.subcapa | Crea una capa CSS con nombre, con una subcapa anidada subcapa. |
@layer nombre1, nombre2, nombre3... | Declara y establece un orden para varias capas CSS. |
@import( fichero.css) layer( nombre) | Importa un archivo CSS y lo introduce en la capa indicada. |
El orden en el que se van a aplicar las capas es a medida que van apareciendo (orden en el que han sido definidas). Esto es muy importante, ya que determina el orden en el que se va a aplicar la especificidad. Sin embargo, veremos más adelante que ese orden se puede alterar.
Veamos cada una de las sintaxis anteriores para entenderlo bien.
Capas con nombre
La forma general de escribir una capa es indicar el nombre a continuación de @layer
, y añadir el código CSS con los estilos en su interior:
@layer reset {
body {
margin: 0;
box-sizing: border-box;
}
}
En este caso, hemos creado una capa llamada reset
, que contiene código CSS para resetear ciertas propiedades. El nombre reset
lo establece el desarrollador, y puede ser el nombre que desee. Esto significa que, a partir de este punto del código, existirá una capa reset
con los estilos indicados.
Capas anónimas
Si en lugar de escribir el nombre de la capa, mantenemos @layer
sin nombre, estaremos creando una capa anónima. Esto es lo mismo que ocurre si colocamos código CSS sin ninguna capa. Al final se creará una capa anónima donde se incluirá ese código CSS:
@layer {
.primary {
background: #34a;
border: 2px outset #6381db;
color: #fff;
padding: 5px 10px;
border-radius: 6px;
}
}
Las capas anónimas, al no tener nombre, no existe ninguna forma de hacer referencia a ellas posteriormente. Recuerda que si creamos múltiples capas anónimas, el navegador las colocará en capas anónimas diferentes.
Capas anidadas
También es posible crear capas dentro de otras (subcapas). Para ello, solo tenemos que utilizar la regla @layer
dentro de otra regla @layer
. También puedes usar una sintaxis rápida separando los nombres de la capa con puntos:
@layer base {
@layer reset {
body {
margin: 0;
box-sizing: border-box;
}
}
}
@layer base.reset {
body {
margin: 0;
box-sizing: border-box;
}
}
Importar CSS en una capa
Si ya conocemos la regla @import, sabremos que es posible utilizarla para importar código CSS de ficheros externos e incorporarlo a nuestra página. Sin embargo, existe una forma de hacerlo añadiéndolo a una capa CSS específica, utilizando la función layer
con el nombre de la capa:
@import url("framework.css") layer(framework);
Esto permitirá que incluso código externo que tengamos separados en diferentes archivos, se pueda colocar directamente en una capa.
Ordenando capas
Hasta ahora hemos visto las diferentes formas de crear capas de cascada en CSS. Básicamente, las capas se van creando a medida que las escribimos, y mantienen el orden de creación:
- 1️⃣ Si no tenemos ninguna regla
@layer
, el navegador mete todo el código en una capa anónima. - 2️⃣ Si tenemos reglas
@layer
, las va creando a medida que las encuentra y mantiene ese orden.
Sin embargo, podemos cambiar el orden de las capas si establecemos una regla
@layer
con los nombres separados por coma. Es importante que este orden, de definirse, tiene que hacerse antes de crear cualquier otra@layer
. Una vez declaradas, no se puede cambiar su orden.
Veamos un ejemplo, donde establecemos un orden concreto en la primera línea. El orden será: primero la capa reset
, luego la capa texts
y luego la capa theme
:
<button class="primary">First button</button>
<button class="primary">Second button</button>
<style>
@layer reset, texts, theme;
@layer reset {
button {
padding: 30px;
}
}
@layer theme {
.primary {
background: #34a;
border: 2px outset #6381db;
color: white;
font-size: 1rem;
padding: 5px 10px;
border-radius: 6px;
}
}
@layer texts {
.primary {
color: red;
}
}
</style>
Centrate en la propiedad color
de texto de la capa theme
y la capa texts
. Si seguimos el orden natural de CSS, debería aplicarse el color blanco (theme), y luego el color rojo (texts). Sin embargo, como hemos reordenado las capas con la primera linea de @layer
, el color blanco prevalece (se aplica después).
Si en el ejemplo anterior, añadieramos al final el siguiente fragmento de código, el navegador fusionaría las dos capas theme
en una misma capa, y entonces el color de texto sería gold
:
@layer theme {
.primary {
color: gold;
}
}
Ten en cuenta que cualquier estilo declarado sin capa, independientemente del orden de aparición, se agrupará en una capa anónima y se aplicará siempre al final del resto de capas declaradas.
¿Para que sirven las capas?
Como hemos visto, las capas nos ayudan a poder reorganizar nuestro código y manejar la especificidad de una forma mucho más flexible. Es muy común, que a medida que el código CSS de nuestra página crece, o se incluye código CSS de librerías de terceros o similar, la especificidad depende de factores dificiles de controlar. Con esta regla @layer
tenemos formas un poco más organizadas de controlar cuando se aplican los estilos.
Observa el siguiente ejemplo. En este código el CSS es muy sencillo. Al ser el mismo selector, se aplica el orden y la herencia, y simplemente se fusionan los estilos, sobreescribiendo el último a los anteriores de coincidir las propiedades:
.primary {
color: red;
}
.primary {
background: #34a;
border: 2px outset #6381db;
color: #fff;
padding: 5px 10px;
border-radius: 6px;
}
.primary {
margin: 20px;
color: gold;
}
<button class="primary">Click me!</button>
Sin embargo, modifiquemos las clases para hacer más específicos los selectores. En cada grupo seleccionamos el mismo elemento pero con diferente especificidad:
- Primer grupo: Botones
button
que tienen un atributoclass
y claseprimary
(especificidad 0,2,1) - Segundo grupo: Botones
button
que tienen claseprimary
. (especificidad 0,1,1) - Tercer grupo: Botones que tienen clase
primary
. (especificidad 0,1,0)
Al contrario que muchos desarrolladores piensan, en CSS no se fusionan los estilos al ser (al fin y al cabo) el mismo elemento, sino que los selectores más especificos son los que tendrán prioridad, independientemente del orden:
button[class].primary {
color: red;
}
button.primary {
background: #34a;
border: 2px outset #6381db;
color: #fff;
padding: 5px 10px;
border-radius: 6px;
}
.primary {
margin: 20px;
color: gold;
}
<button class="primary">Click me!</button>
En este caso, se aplicará primero el último grupo (al ser el menos especifico), luego se aplicarán los estilos del segundo grupo, sobreescribiendo el color blanco por el color dorado. Por último, el primer bloque sobreescribirá con el color rojo.
Modifiquemos un poco el ejemplo anterior, y vamos a añadir el primer grupo en una capa llamada texts
:
@layer texts {
button[class].primary {
color: red;
}
}
button.primary {
background: #34a;
border: 2px outset #6381db;
color: #fff;
padding: 5px 10px;
border-radius: 6px;
}
.primary {
margin: 20px;
color: gold;
}
<button class="primary">Click me!</button>
Ahora, observa que la capa texts
creada será la primera en procesarse por el navegador. Lo primero que hará es agrupar todos los estilos en dicha capa, calcular sus especificidades y aplicarlas. Luego, buscará si existen otras capas diferentes para procesarlas. Si no existen más, agrupará el resto de los estilos fuera de capas en una capa anónima y los aplicará después de los anteriores.
De esta forma, hemos cambiado el comportamiento que explicamos al principio por algo que, unido a la posibilidad de agrupar en diferentes capas y ordenar mediante la regla @layer
se convierte en un recurso muy potente para organizar código por parte de los desarrolladores.
Capas con nesting CSS
Gracias al nesting CSS nativo, también es posible utilizar la regla @layer
a la inversa, es decir, crear nuestro código CSS en un selector y escribir las reglas @layer
en su interior. Veamos un fragmento de código de ejemplo:
<div class="primary">Hello, friend!</div>
<style>
@layer base, theme;
.primary {
@layer theme {
background: indigo;
color: white;
}
@layer base {
background: grey;
width: 250px;
height: 200px;
padding: 1rem;
}
}
</style>
Puedes cambiar la primera línea @layer base, theme
por @layer theme, base
. Esto hará que el orden de las capas sea diferente y aplique primero la capa theme
y luego la capa base
.