Javascript y CSS

Cómo usar código Javascript en CSS


En el artículo anterior vimos las formas generales de usar CSS en Astro. Sin embargo, hay casos muy concretos y dudas frecuentes donde lo anterior se puede quedar corto. Por ejemplo, ¿qué ocurre si queremos utilizar un dato de Javascript en el CSS de Astro? ¿Cuál es la mejor forma de hacerlo? ¿Cómo pasamos un estilo CSS desde un componente a otro?

Veamos algunas formas que pueden facilitarnos estas tareas.

Compartir clases por props

En el desarrollo web, la forma más extendida de dar estilo a los elementos es mediante clases. Es por ello, que probablemente, la forma más intuitiva sea utilizar el atributo class. Astro, por defecto, no pasa los atributos class de un componente a otro:

---
import "../components/Component.astro";
---

<Component class="danger" />

A pesar de haber indicado el atributo class a nuestro componente, este no lo utilizará. Esto ocurre porque para Astro, el atributo class es realmente una prop class. Por lo que podemos aprovechar esto para reutilizarlo:

---
const { class: className } = Astro.props;
---

<div class={className}>
  <p>...</p>
</div>

Observa que desde nuestro componente, obtenemos la prop class y la asignamos a una variable className, ya que class es una palabra reservada de Javascript y no se puede utilizar. Luego, simplemente asignamos className al atributo class de nuestro HTML.

Definir clases con class:list

Ahora imaginemos que la información la tenemos en Javascript y queremos pasarla a nuestro componente. Podemos hacerlo de varias formas, pero los atributos class:list son bastante interesantes en este escenario:

---
const list = ["container", "danger"];
const isDanger = true;
---
<div class:list={list}>
  <p class:list={ red: isDanger }>
    ...
  </p>
</div>

En este ejemplo tenemos lo siguiente:

  • 1️⃣ class:list={list} leerá el array y añadirá cada uno de los valores en una lista de clases.
  • 2️⃣ class:list={ red: isDanger } leerá el objeto isDanger y si es verdadero, añadirá red como clase.

El código final quedaría algo similar a esto:

<div class="container danger">
  <p class="red">
    ...
  </p>
</div>

Definir variables con define:vars

Otra forma bastante habitual en relación a los estilos es utilizando Variables CSS. Veamos como podemos utilizarlas en nuestros componentes de Astro, obteniendo la información desde Javascript:

---
const backgroundColor = "indigo";
const color = "white";
---

<style define:vars={{ backgroundColor, color }}>
  h1 {
    background-color: var(--backgroundColor);
    color: var(--color);
  }
</style>
<h1>¡Hola, amigo!</h1>

Observa que utilizamos define:vars para pasarle las variables que tenemos en Javascript. Astro obtiene esta informacíón y las convierte a variables CSS con el mismo nombre proporcionado, por lo que podemos utilizarlas sin problema.

Estilos en línea

Aunque suele ser preferible utilizar variables CSS siempre que sea posible, podemos utilizar estilos en linea de forma muy similar a lo anterior:

---
const backgroundColor = "indigo";
const color = "white";
---
<div style={{ backgroundColor, color }}>
  <p>¡Hola, amigo!</p>
</div>

Estilos directos con is:inline

Como hemos visto hasta ahora, generalmente Astro procesa y revisa los estilos CSS haciendo ciertas modificaciones que generalmente son buenas para optimizar el rendimiento de nuestros componentes. Sin embargo, en algunas ocasiones, estas optimizaciones pueden entorpecer nuestros estilos o crear comportamientos que no buscamos debido a este procesamiento.

Podemos utilizar un atributo is:inline en nuestros bloques <style> para indicarle a Astro que no procese el CSS indicado en ese bloque, sino que lo inserte directamente en un <style> en nuestro HTML.

Esto puede ser muy útil en algunas situaciones:

  • 1️⃣ Necesitamos estilos CSS críticos que deben renderizarse prioritariamente.
  • 2️⃣ Componentes que tienen muy pocos estilos y no merece la pena crear otro archivo .css.
  • 3️⃣ No depender de archivos .css externos.

Por otro lado, tiene algunas posibles desventajas:

  • 💔 Los estilos son globales, no están scoped al componente.
  • 💔 No permite utilizar :global(), ya que no es procesado por Astro.
  • 💔 Si usamos preprocesadores, no es preprocesado.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev