CSS @layer: ¿Héroe o amenaza?
Tags: webdev, css
Published: 2024-03-18 05:04:11

La vida del developer es una vida donde siempre vas a estar aprendiendo. Ya sea por los cambios constantes del mercado, la organización, nuevas tools que te ayudan a hacer mejor tu trabajo, nuevas features que se remueven/agregan a la plataforma o alguna IA que te va a robar el trabajo (saludos al Devin XD)

Hoy vamos a hablar de [@layer](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer), una regla de CSS que viene a resolver uno de los tantos "problemas" que podemos tener en la creación de estilos ... "LA ESPECIFICIDAD".

En si no hay ningún problema pero cuando manejamos aplicaciones grandes es complicado manejar la especificidad. Si bien podemos usar metodologías para organizar nuestro CSS y controlar el origen y la especificidad; hay una pieza faltante que esta regla puede resolver ... definir la prioridad (sin usar `!important`) de manera consistente.

![Meme: ah caray eso si me interesa](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gwa8r6n3o1ontlhyccaf.png)

## CSS at-rule @layer

`@layer` esta en [baseline](https://developer.mozilla.org/en-US/blog/baseline-unified-view-stable-web-features/) desde 2022, aunque en algunos Browsers de Android se agregó hasta marzo de 2024 (según [caniuse](https://caniuse.com/mdn-css_at-rules_layer)).

Antes de continuar, quiero que hagamos 2 cosas simples:

1. Cada vez que te veas el texto "Atinale al color", lee el código y responde cual color será el del elemento.
2. Realiza el ejercicio y verifica la respuesta.

Para mi es como un juego, te podría sorprender y ciertamente hará esto menos aburrido.

Ahora si, haremos varios mini demos simples pero inquebrantables.

Primero crea un `index.html` con el siguiente contenido

```html
<html>
  <head>
      <link rel="stylesheet" href="layer.css">
  </head>
  <body>
    <main class="main" />
  </body>
</html>
```

Y ahora vamos crear un archivo `layer.css` y agregar el siguiente código

```css
@layer {
  .main {
    background: blue;
  }  
}

.main {
  height: 50px;
}
```

Atinale al color

**SPOILER ALERT**

..........

Creo que estuvo fácil o quizás no, es azul.

Y si cambias por este código?

```css
@layer theme {
  .main {
    background: blue;
  }  
}

.main {
  height: 50px;
}
```

Atinale al color

**SPOILER ALERT**

..........

Esto es juego de niños, es azul.

![Meme: Y eso que decian que nunca iba a servir para nada](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tqgrte3s0ruuvxvladrr.png)

Ahora, un poco de explicación teoría aburrida. `@layer` es una [CSS at-rule](https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule), quiere decir que esta internamente tiene un bloque de código y esta puede tener un nombre o no tenerlo. 

Y si cambias por este código?

```css
@layer theme {
  .main {
    background: blue;
  }  
}

@layer dummy {
  .main {
    background: red;
  }  
}

.main {
  height: 50px;
}
```

Atinale al color

**SPOILER ALERT**

..........

Too easy, es rojo, seguramente te estas replanteando que haces aún aquí leyendo esto, vamos hacerlo más interesante. Cuando usas `@layer`, las declaraciones posteriores siempre tendrán mas prioridad que las primeras.

```css
@layer theme {
  main.main {
    background: blue;
  }  
}

@layer dummy {
  .main {
    background: red;
  }  
}

.main {
  height: 50px;
}
```

Atinale al color


![Meme: asustado potter? ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/og4ujfheo6ndu04rb9s5.png)

**SPOILER ALERT**

..........

Probablemente si nos basamos en la espeficidad tu respuesta fue azul, pero la regla `@layer` lo que predomina es el orden no la especificidad, incluso si agregaras un id en el selector del layer **theme** funcionaría igual (hazlo para que veas que no te miento).

Here we go again

```css
@layer theme {
  .main {
    background: blue !important;
  }  
}

@layer dummy {
  .main {
    background: red;
  }  
}

.main {
  height: 50px;
}
```

Atinale al color

**SPOILER ALERT**

..........

Recuerden, la cascada es la que determina que estilos se aplican. En esta se toma en cuenta la ubicación y la importancia. En este caso la `@layer theme` aplica un estilo con `!important`, eso hace que el orden e incluso la especificidad no importen.

Esto se puso mas interesante

```css
@layer theme {
  .main {
    background: blue !important;
  }  
}

@layer dummy {
  .main {
    background: red !important;
  }  
}

.main {
  height: 50px;
}
```

Atinale al color

![Meme: por fin un digno oponente](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qwn8hizpj54gaozl1ajo.png)

**SPOILER ALERT**

..........

Seguro pensaste que era rojo, yo también lo pensé pero al parecer una layer que aplique un estilo con `!important` prevalecerá sobre otro que venga después, sin importar la especificidad. Es por eso que `@layer` puede ser héroe o villano. Aunque si usas layers, el uso de `!important` debería estar prohibido.

Esto se puso interesante

```css
@layer dummy, theme;

@layer theme {
  .main {
    background: blue;
  }  
}

@layer dummy {
  .main {
    background: red;
  }  
}

.main {
  height: 50px;
}
```

Atinale al color

**SPOILER ALERT**

![Meme: tranquilo tampoco lo entendí a la primera](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nspxmhbcmtnws1o32kna.png)

..........

@layer se puede declarar e inmediatamente colocar un bloque o puede declararse y posteriormente definir el bloque. El orden en que se definan le dara la prioridad. Recuerda las primeras siempre tendrán menos priordad que las últimas. Por ende el color es azul, aunque solo se hubiera puesto `@layer dummy`; hubiera dado el mismo resultado

Vamos con otro, ya casi llegamos al final

```css
@layer theme {
  .main {
    background: blue;
  }  
}

@layer dummy {
  main.main {
    background: red;
  }  
}

.main {
  background: green;
  height: 50px;
}
```

Atinale al color

**SPOILER ALERT**

..........

Y el color es ...

![Meme: verde, verde como que?](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b6x93cmmp3wlkte2u3os.png)

Verde. Los estilos fuera de las capas tie[](url)nen mayor prioridad que las que tienen capas, incluso aunque pusieras la declaración de estilos antes de la declaración de @layer tendría exactamente los mismos efectos, a menos que usaras !important. Lo cual agrega mayor prioridad, vamos intentalo.

Ok, ya estamos cerca del final, este es el último mini demo, respira hondo, vacia tu mente, deja que tu mente fluya por la cascada, se la cascada

```css
@layer dummy, theme;

@layer theme {
  .main {
    background: blue !important;
  }
}

@layer dummy {
  main.main {
   background: red;
  }
}

main.main {
  background: green !important;
  height: 50px;
}
```

Atinale al color

SPOILER ALERT

![Meme: era yo azul](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/grl0r0n2xsnkajt1do0l.jpeg)

..........

Casi podría apostar que pensaste que era verde, es mas si lo pensaste mandame un [tweet](https://twitter.com/DezkaReid), mencioname en un [post](https://www.linkedin.com/in/joelhumberto/) o lo que mas te agrade y pon "Yo también pensé que era verde". Pero es azul, recuerda `!important` define prioridad, pero cuando 2 estilos son importantes el origen de donde se declara tiene más relevancia.

Cada `@layer` puede tener incluso nested layer pero no abordaremos ese tema en este momento, porque ya me extendí y hay algo muy importante que debo decirte antes.

Bueno ahora la parte mas importante de este post, no es seguro usar este feature de momento si mantienes una misma base de código o estilos para mobile :(

Si bien esta disponible desde 2022, si una buena parte de tu mercado es Android probablemente no sea buena idea usarla, revisa caniuse y el tipo de usuarios que llegan a tus aplicaciones para saber si es seguro usarla.

En este caso `@supports` no nos va a servir, porque esta solo evualua si un estilo es válido no tiene soporte para [at-rules](https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule). Este soporte esta en [discusión](https://github.com/w3c/csswg-drafts/issues/6966), así que mientras tanto el uso de `@supports at-rule(@layer)` tiene un futuro incierto.

Podríamos usar Javascript para saber si tiene soporte

```javascript
if (typeof CSSLayerBlockRule !== 'undefined') {
  console.log("Si tenemos soporte :D");
}
```

Pero esto solo agregaría un blocker mas al parsing y al rendering, ademas de tener que generar estilos que soporten `@layer` y un fallback que no, mucha arquitectura que podría no valer la pena. Pero como dije, todo dependerá de nuestros usuarios.

Gracias por llegar hasta aquí, te dejo un [pen](https://codepen.io/dezkareid/pen/oNOYQeP) con un código similar al del último mini demo, si puedes comparte y espero que hayas aprendido algo (aunque no vayas a usar esta feature)