react-aplicar-estilos-css

Cómo aplicar CSS en React

  • 5 min

Hasta ahora, nos hemos centrado en que nuestra aplicación de React funcione y gestione datos. Pero, no hemos hecho nada estéticamente, así que se ven horribles.

Ha llegado el momento de ponerlas bonitas y aplicarles estilos, más que nada para que no parezcan documentos de Word de los años 90.

En el mundillo de React existen muchas de formas de aplicar estilos (SASS, Styled Components, Tailwind, Emotion…). Muchas de ellas ni siquiera se usan ya.

En cualquier caso, lo más importante es empezar por lo estandard, buen CSS estándard de toda la vida.

La buena noticia es que si ya sabéis CSS, ya sabéis estilizar en React. Solo hay un par de reglas sintácticas que cambian.

De class a className

La primera bofetada que os dará React si copiáis y pegáis código HTML antiguo es esta:

Warning: Invalid DOM property class. Did you mean className?

Como vimos en los primeros capítulos, JSX es JavaScript, no HTML. Y en JavaScript, la class es una palabra reservada… así que no podemos usarla.

Para evitar conflictos de sintaxis, React decidió renombrar el atributo HTML class a className.

// ❌ HTML / React Incorrecto
<div class="contenedor">...</div>

// ✅ JSX Correcto
<div className="contenedor">...</div>
Copied!

Por lo demás, funciona exactamente igual. Acepta una cadena de texto con los nombres de las clases que queráis aplicar.

Clases dinámicas

La gran ventaja de React es que className es solo una prop más. Podemos usar JavaScript para decidir qué clases aplicar en tiempo real.

Si solo tenemos dos estados (por ejemplo, activo/inactivo), un ternario dentro de un Template Literal es lo más rápido.

function Item({ isActive }) {
  return (
    <div className={`item ${isActive ? 'item-active' : ''}`}>
      Contenido
    </div>
  );
}
Copied!

Fijaos en el espacio en blanco después de ‘item ’, es necesario para que no se peguen las clases (itemitem-active)

Si la lógica se complica, usar strings concatenados es un dolor. Usar arrays puede ser más elegante.

const clases = [
  'btn',
  props.primary ? 'btn-primary' : '',
  props.large ? 'btn-lg' : ''
];

// Filtramos los vacíos y unimos con espacios
return <button className={clases.filter(Boolean).join(' ')}>Click</button>;
Copied!

En proyectos reales, casi todos usamos una pequeña librería llamada clsx o classnames. Es como una “evolución bien hecha” de ejemplo anterior del array.

Nos permite escribir clases condicionales de forma mucho más legible, y la sintaxis se ha convertido casi en un estándard.

import clsx from 'clsx';

// El resultado es un string limpio con las clases
const className = clsx('btn', {
  'btn-primary': isPrimary,
  'btn-disabled': isDisabled,
  'btn-loading': isLoading
});
Copied!

Importando hojas de estilo

Para importar un fichero .css, en desarrollo web tradicional, añadimos una etiqueta <link> en el head de nuestro HTML.

En React (especialmente con Vite), importamos el CSS directamente en nuestros archivos JavaScript.

Imaginad que tenemos un componente Boton.jsx. Podemos crear un archivo Boton.css junto a él.

/* Boton.css */
.btn-primary {
  background-color: blue;
  color: white;
  padding: 10px 20px;
  border-radius: 5px;
}
Copied!

Y en nuestro componente, simplemente importamos el archivo:

// Boton.jsx
import React from 'react';
import './Boton.css'; // <--- AQUÍ  

export default function Boton() {
  return <button className="btn-primary">Click me</button>;
}
Copied!

Cuando Vite detecta esa importación, coge el CSS, lo procesa y lo inyecta automáticamente en el navegador (generalmente añadiendo una etiqueta <style> en el head o generando un archivo .css final en producción).

El problema del Global Scope

Aunque hayáis importado Boton.css dentro de Boton.jsx, los estilos NO están encapsulados, todo es global.

Es decir, que si definís la clase .tarjeta en Boton.css y también definís .tarjeta en Header.css, ambas reglas chocarán.

Ganará la que se haya cargado en último lugar (es parte del funcionamiento de la “Cascada” de CSS). En nuestro caso, básicamente una random.

Importar un CSS en un componente solo sirve para organizar vuestros archivos. No aísla los estilos.

Un estilo importado en el componente más profundo de la app afectará al componente más externo si los nombres de clase coinciden.

Para evitar esto usando CSS tradicional, una forma es ser muy disciplinados con las nomenclaturas. Así surgen metodologías como BEM (Block Element Modifier):

/* Usando BEM para evitar colisiones */
.Boton__container--primary { ... }
.Header__title { ... }
Copied!

En general, es bastante horrible. A mi personalmente no me gusta BEM.

Veremos otras soluciones en las próximas entradas.

Estilos en línea (style)

Aunque este artículo va de clases, vale la pena mencionar que también podéis aplicar estilos directos con la prop style.

A diferencia de HTML (donde style es un string), en React style acepta un objeto JavaScript. Las propiedades CSS con guiones se convierten a camelCase.

// HTML: <div style="background-color: red; margin-top: 10px;">

// React
const estilos = {
  backgroundColor: 'red', // camelCase
  marginTop: '10px'       // camelCase
};

return <div style={estilos}>Hola</div>;
Copied!

¿Cuándo usar style inline? Como norma general, evitar los estilos en línea. Ensucia el código y no permite media queries ni pseudoselectores (:hover).

Usadlo solo para valores dinámicos calculados (ej: coordenadas x,y de un elemento arrastrable, una imagen de fondo dinámica o una barra de progreso).