Tailwind CSS: diseño utility-first
Tailwind CSS es un framework que construye interfaces combinando clases utilitarias de un solo propósito directamente en el HTML. Este tutorial cubre instalación, spacing, layouts, responsive, dark mode y customización con la versión 4. Prerequisito conceptual: HTML y CSS.
¿Qué es Tailwind?
A diferencia de Bootstrap, que trae componentes predefinidos, Tailwind es utility-first: cada clase aplica una única propiedad (p-4 es solo padding de 1rem). Tú compones la interfaz combinando estas clases en el HTML, sin escribir CSS en archivos separados.
- Velocidad: estilizas sin cambiar de archivo ni inventar nombres de clase.
- Consistencia: el spacing, la tipografía y los colores vienen de un design system único.
- Solo lo que usas: el CSS final se genera con las clases detectadas en tu código; no hay CSS muerto.
- Responsive integrado: los prefijos
sm:,md:ylg:viven en la misma clase.
@tailwindcss/vite y una directiva @import "tailwindcss" en tu CSS. Todo lo de este tutorial usa v4.Instalación
Con Vite
En un proyecto Vite (React, Vue, vanilla), se instala el paquete y su plugin:
npm install tailwindcss @tailwindcss/vite
// vite.config.ts
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})
// En tu CSS principal (src/index.css):
@import "tailwindcss";Con Next.js
Con Next.js (App Router o pages router) se usa el PostCSS plugin que ya trae el paquete, o el plugin experimental de Vite según tu versión. Para v4 el método estándar:
npm install tailwindcss @tailwindcss/postcss
// postcss.config.mjs
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};
// En tu CSS global (globals.css):
@import "tailwindcss";tailwind.config.js obligatorio ni la directiva @tailwind base/components/utilities. Todo se configura desde CSS con @theme y la detección de contenido es automática. Si migras desde v3, revisa la guía oficial de migración.Spacing y tipografía
El spacing usa una escala fija: cada unidad equivale a 0.25rem (4px). p-4 son 1rem, mt-2 es margin-top de 0.5rem:
<div class="p-4">
<!-- padding: 1rem en los 4 lados -->
<button class="px-6 py-2 m-2">
<!-- px: horizontal, py: vertical, m: margin -->
</button>
</div>
<!-- Equivalencias de la escala -->
p-0 = 0px
p-1 = 0.25rem (4px)
p-2 = 0.5rem (8px)
p-4 = 1rem (16px)
p-8 = 2rem (32px)
p-16 = 4rem (64px)La tipografía también tiene escala: text-sm, text-base, text-2xl... y pesos con font-*:
<h1 class="text-3xl font-bold tracking-tight">Título</h1>
<p class="text-sm text-gray-600 leading-relaxed">
Párrafo con interlineado relajado y color gris.
</p>
<span class="font-mono text-xs uppercase">CÓDIGO</span>Utilidades útiles de texto: text-center, truncate (ellipsis), whitespace-nowrap y leading-* para interlineado.
Flexbox y Grid
Los dos sistemas de layout se declaran con una clase y se ajustan con utilidades. Flexbox:
<div class="flex items-center justify-between gap-4">
<div class="flex items-center gap-2">
<img class="w-8 h-8 rounded-full" src="avatar.jpg" alt="" />
<span class="font-medium">Ana García</span>
</div>
<button class="px-4 py-2 bg-blue-600 text-white rounded-lg">
Seguir
</button>
</div>flex— display flex.items-center— alinea verticalmente.justify-between— separa los hijos con espacio entre ellos.gap-4— espacio entre hijos.flex-1— el hijo crece para ocupar el espacio restante.
Grid:
<div class="grid grid-cols-3 gap-4">
<div class="p-4 bg-white rounded-xl shadow">Item 1</div>
<div class="p-4 bg-white rounded-xl shadow">Item 2</div>
<div class="p-4 bg-white rounded-xl shadow">Item 3</div>
</div>
<!-- Variantes útiles -->
grid-cols-1 → 1 columna
grid-cols-3 → 3 columnas iguales
grid-cols-[200px_1fr] → columnas explícitas
col-span-2 → el hijo ocupa 2 columnas
grid-flow-row / grid-flow-col → direcciónflex para barras y filas de un solo eje, grid para rejillas de tarjetas y columnas. Y ambos aceptan gap-*, así que olvídate de los márgenes negativos.Responsive
Los prefijos sm:, md:, lg: y xl: aplican la utilidad solo desde ese breakpoint en adelante (mobile-first):
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<!-- 1 columna en móvil, 2 en tablet, 4 en escritorio -->
</div>
<p class="text-sm md:text-base lg:text-lg">
El texto crece con la pantalla.
</p>
<div class="flex flex-col md:flex-row gap-4">
<!-- Apilado en móvil, fila en escritorio -->
</div>Los breakpoints por defecto en v4: sm 640px, md 768px, lg 1024px, xl 1280px, 2xl 1536px. Como es mobile-first, md:grid-cols-2 significa "desde 768px en adelante".
@theme con --breakpoint-*.Estados
Las variantes de estado prefijan la utilidad: hover:, focus:, active:, disabled::
<button
class="px-4 py-2 bg-blue-600 text-white rounded-lg
hover:bg-blue-700 active:scale-95
focus:outline-none focus:ring-2 focus:ring-blue-300
disabled:opacity-50"
>
Guardar
</button>group-hover: aplica estilo a un hijo cuando se hace hover en un ancestro marcado con group. Es la base de tarjetas y menús que reaccionan al pasar el ratón:
<a class="group block p-4 rounded-xl hover:bg-gray-50">
<h3 class="font-semibold group-hover:text-blue-600">
Aprende Tailwind
</h3>
<p class="text-sm text-gray-500 opacity-0 group-hover:opacity-100 transition-opacity">
Texto que aparece al hacer hover.
</p>
</a>Otras variantes muy usadas: focus-within: (para contenedores de formularios), peer-* (hermanos previos), first:/last: (listas) y even:/odd: (filas alternas).
Dark mode
La variante dark: aplica estilos cuando el sistema (o el HTML) está en tema oscuro:
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
<p class="text-gray-600 dark:text-gray-400">
Se adapta automáticamente al tema.
</p>
</div>En v4, por defecto el dark mode usa la media query prefers-color-scheme: funciona siguiendo la configuración del sistema. Si quieres un toggle manual, configúralo con un selector:
/* globals.css — dark mode basado en clase .dark */
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
/* Ahora dark: responde a la clase .dark en el <html> */
<html class="dark">
<div class="bg-white dark:bg-gray-900">
Oscuro cuando html lleva la clase .dark
</div>
</html><head> lee el valor guardado (localStorage) y añade/elimina la clase .dark del <html> antes del primer paint, evitando un flash del tema equivocado.Customización
En v4, todo el tema se declara en CSS con @theme. Define tus propios colores, fuentes y breakpoints, y Tailwind genera las utilidades correspondientes automáticamente:
/* globals.css */
@import "tailwindcss";
@theme {
/* Un color nuevo → utilidades bg-marca, text-marca, border-marca... */
--color-marca: #ff5c1a;
--color-marca-claro: #ffd9c4;
/* Una fuente nueva → font-display */
--font-display: "Sora", sans-serif;
/* Un breakpoint nuevo → 3xl: */
--breakpoint-3xl: 1800px;
}
/* Uso en el HTML */
<h1 class="font-display text-marca">Título con tu identidad</h1>
<div class="bg-marca-claro p-4 rounded-xl">Panel</div>También puedes sobrescribir la escala de colores existente con las variables estándar (--color-*) y el spacing (--spacing-*), ajustando la base de toda la escala:
@theme {
/* Cambia la base del spacing: p-4 pasa de 1rem a 1.25rem */
--spacing: 0.3125rem;
}@apply sigue existiendo para componer utilidades en CSS propio, pero v4 recomienda preferir clases en el HTML. Usa @apply con moderación (por ejemplo, en estilos de componentes de terceros) — el abuso vuelve a crear el problema de "archivos CSS separados" que Tailwind pretende eliminar.Componentes con @layer
Para clases propias reutilizables (un botón, una tarjeta) se usa @layer components junto con @apply. Así el CSS generado queda ordenado en capas y respeta la precedencia de las utilidades:
/* globals.css */
@import "tailwindcss";
@layer components {
.btn-primario {
@apply inline-flex items-center gap-2 px-4 py-2
bg-blue-600 text-white text-sm font-medium
rounded-lg hover:bg-blue-700 active:scale-95
focus:outline-none focus:ring-2 focus:ring-blue-300;
}
.tarjeta {
@apply p-6 bg-white dark:bg-gray-800 rounded-2xl
border border-gray-200 dark:border-gray-700 shadow-sm;
}
}
<!-- Uso -->
<button class="btn-primario">Guardar</button>
<div class="tarjeta">Contenido de la tarjeta</div>@layer: las utilidades (capas utilities) ganan a los componentes en CSS. Esto significa que class="tarjeta p-0" funciona: la utilidad p-0 sobreescribe el padding del componente sin problemas de especificidad.Con estas piezas tienes el ciclo completo: clases utilitarias para el día a día, variantes para estados y responsive, @theme para tu identidad y @layer components para los patrones que se repiten. Todo desde un solo lenguaje que vive en el HTML.
Ejercicios
Tailwind cambia la forma de pensar el CSS: en lugar de nombrar clases y mantener hojas de estilo, compones interfaces directamente con utilidades. La v4 lo hace más simple todavía con configuración en CSS puro. Es la herramienta con la que se construyen la mayoría de interfaces modernas — y cuanto más la uses, más natural resulta.