Módulo 00: Introducción a Tailwind CSS
Objetivos del módulo
- Explicar qué es Tailwind CSS y qué no es
- Crear una primera página con Tailwind en un solo fichero HTML, sin instalar nada
- Entender el enfoque utility-first y compararlo con el CSS semántico y con Bootstrap
- Saber cómo se genera el CSS a partir de las clases que escribes
- Conocer la historia del proyecto y qué cambió por dentro con Oxide
- Valorar con criterio las ventajas y las críticas de Tailwind
- Decidir entre Tailwind 4.3 y Tailwind 3.4 según tus navegadores y tu proyecto
- Saber qué se pierde en v3 y qué hacer en su lugar
- Leer las marcas 🆕 y 🔄 que usa este curso
- Situar cada tema en el mapa del curso
1. Qué es Tailwind CSS
Tailwind CSS es un framework de CSS formado por miles de clases pequeñas, cada una con una sola tarea. En lugar de escribir una regla CSS para cada elemento, le aplicas clases directamente en el HTML:
<p class="mt-4 text-sm font-semibold text-gray-600">Envío gratis desde 50 €</p>
Cada clase equivale a muy poco CSS:
| Clase | Qué hace | CSS equivalente |
|---|---|---|
mt-4 | Margen superior | margin-top: 1rem |
text-sm | Texto pequeño | font-size: 0.875rem y su altura de línea |
font-semibold | Seminegrita | font-weight: 600 |
text-gray-600 | Texto gris | color con el gris 600 de la paleta |
A estas clases se las llama utilidades (utilities). No describen qué es el elemento, como haría .aviso-envio, sino qué aspecto tiene. Lo decidido por el diseño queda escrito en el propio HTML, y no necesitas abrir una hoja de estilos para cada cambio.
📘 Concepto: Utility-first significa construir la interfaz combinando utilidades como primera opción. Solo extraes tus propias clases o componentes cuando hay una razón real, y eso se aprende en el módulo 16.
Qué no es Tailwind
Aclarar esto evita muchas confusiones al empezar:
- No es una biblioteca de componentes. No existe una clase
buttonnicard. Si quieres un botón, lo construyes combinando utilidades. Las bibliotecas de componentes hechas con Tailwind son proyectos aparte. - No es JavaScript en el navegador. En producción, Tailwind se ejecuta al compilar y lo que llega al usuario es un fichero
.cssnormal. La única excepción es el modo de pruebas que usarás en la sección siguiente. - No te ahorra saber CSS.
flex,gridostickyson propiedades de CSS con otro nombre. Si no sabes qué haceposition: sticky, la clasestickytampoco te lo va a explicar. Si necesitas una base, consulta el Curso de HTML y CSS. - No es un tema visual. Una web hecha con Tailwind no tiene por qué parecerse a otra. Tailwind aporta una paleta y unas escalas, pero el diseño lo pones tú.
Licencia y modelo del proyecto
El paquete tailwindcss es software libre con licencia MIT. Lo mantiene la empresa Tailwind Labs, que vende productos de pago aparte, como Tailwind Plus, una colección de plantillas y componentes de la que hablaremos en el módulo 20. Nada de lo que aprenderás en este curso requiere pagar.
2. Tu primera página en dos minutos 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4) el CDN de desarrollo tiene otra dirección. Si usas la LTS: sustituye la etiqueta
<script>por<script src="https://cdn.tailwindcss.com"></script>, que hoy sirve la 3.4.17; el resto del ejemplo funciona igual.
La forma más rápida de probar Tailwind es un único fichero HTML con un <script> que compila las clases dentro del navegador. Crea primera.html y ábrelo con doble clic:
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<title>Mi primera página con Tailwind</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
</head>
<body class="flex min-h-screen items-center justify-center bg-slate-100">
<div class="rounded-2xl bg-white p-8 text-center shadow-lg">
<h1 class="text-3xl font-bold text-indigo-700">Tienda EMPRESA</h1>
<p class="mt-2 text-gray-600">Mi primera página con Tailwind CSS</p>
<button class="mt-6 rounded-lg bg-indigo-600 px-5 py-2 font-semibold text-white hover:bg-indigo-700">
Ver catálogo
</button>
</div>
</body>
</html>

Figura 1. Resultado real de primera.html. No hay ningún CSS escrito a mano.
Lee las clases de izquierda a derecha y verás que describen la pantalla:
| Clases | Elemento | Qué consiguen |
|---|---|---|
flex min-h-screen items-center justify-center | <body> | Ocupa toda la ventana y centra su contenido en los dos ejes |
bg-slate-100 | <body> | Fondo gris azulado muy claro |
rounded-2xl bg-white p-8 text-center shadow-lg | Tarjeta | Esquinas redondeadas, fondo blanco, relleno, texto centrado y sombra |
text-3xl font-bold text-indigo-700 | Título | Tamaño, peso y color |
mt-2 text-gray-600 | Párrafo | Separación con el título y color |
rounded-lg bg-indigo-600 px-5 py-2 ... | Botón | Forma, color y relleno horizontal y vertical |
hover:bg-indigo-700 | Botón | Oscurece el fondo solo al pasar el ratón |
Cambia indigo por emerald en el título y en el botón y recarga. Has cambiado el color sin tocar ningún CSS.
Fíjate en hover:bg-indigo-700: esa parte hover: es una variante, y es lo que convierte a las utilidades en algo más potente que el atributo style. Volveremos a ello en la sección 3 y las estudiaremos a fondo en el módulo 11.
⚠️ Importante: Este
<script>es solo para probar y aprender. Compila en cada carga de página dentro del navegador del usuario, así que nunca debe llegar a producción. En el módulo 01 instalarás Tailwind con Vite, que es como se trabaja de verdad. Mientras tanto, con el CDN puedes seguir todos los ejemplos de este módulo.
3. Utility-first frente a CSS semántico y Bootstrap
Para comparar con honestidad hay que construir lo mismo de las tres maneras. Vamos a hacer la tarjeta de un producto real de la tienda: el Teclado mecánico, de 79,90 €.
Descarga esta imagen y guárdala como img/teclado.svg junto a tus ficheros HTML: 00-img-teclado.svg.
Figura 2. La diferencia de fondo es dónde se decide el aspecto de cada elemento.
Enfoque 1: CSS semántico
Es el enfoque clásico. El HTML dice qué es cada cosa y el CSS dice cómo se ve. Aquí se usa la convención BEM (bloque, elemento, modificador) para organizar los nombres:
<article class="producto">
<img class="producto__imagen" src="img/teclado.svg" alt="Teclado mecánico retroiluminado">
<div class="producto__cuerpo">
<span class="producto__etiqueta">Periféricos</span>
<h2 class="producto__nombre">Teclado mecánico</h2>
<p class="producto__descripcion">Teclado mecánico retroiluminado</p>
<div class="producto__pie">
<strong class="producto__precio">79,90 €</strong>
<a class="producto__boton" href="#">Añadir</a>
</div>
</div>
</article>
/* semantico.css */
.producto {
max-width: 24rem;
overflow: hidden;
border: 1px solid #e5e7eb;
border-radius: 0.75rem;
background-color: #fff;
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
font-family: system-ui, sans-serif;
}
.producto__imagen {
display: block;
width: 100%;
height: 12rem;
object-fit: cover;
}
.producto__cuerpo {
padding: 1.25rem;
}
.producto__etiqueta {
display: inline-block;
padding: 0.125rem 0.625rem;
border-radius: 9999px;
background-color: #e0e7ff;
color: #3730a3;
font-size: 0.75rem;
font-weight: 600;
}
.producto__nombre {
margin: 0.75rem 0 0;
color: #111827;
font-size: 1.25rem;
font-weight: 700;
}
.producto__descripcion {
margin: 0.25rem 0 0;
color: #4b5563;
font-size: 0.875rem;
}
.producto__pie {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 1rem;
}
.producto__precio {
color: #111827;
font-size: 1.5rem;
font-weight: 700;
}
.producto__boton {
padding: 0.5rem 1rem;
border-radius: 0.5rem;
background-color: #4f46e5;
color: #fff;
font-size: 0.875rem;
font-weight: 600;
text-decoration: none;
}
.producto__boton:hover {
background-color: #4338ca;
}
El HTML queda limpio y legible, y esa es su gran virtud. Sus costes aparecen con el tiempo:
- Hay que inventar nombres para todo, incluso para envoltorios sin significado como
producto__pie. - Se salta entre dos ficheros para cada cambio pequeño.
- Cuesta borrar. Nadie se atreve a eliminar una regla si no sabe qué páginas la usan, y la hoja de estilos solo crece.
- Los valores se dispersan. Sin disciplina acabas con
0.8rem,0.85remy14pxen el mismo proyecto, porque cada regla decide el suyo.
Muchos equipos usan este enfoque con excelentes resultados, sobre todo apoyándose en variables CSS y en CSS moderno. No es un enfoque superado: es una opción con otros costes.
Enfoque 2: Bootstrap
Bootstrap trae componentes terminados. Enlazas su hoja de estilos y usas sus clases:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css">
<article class="card shadow" style="max-width: 24rem">
<img class="card-img-top" src="img/teclado.svg" alt="Teclado mecánico retroiluminado">
<div class="card-body">
<span class="badge rounded-pill text-bg-primary">Periféricos</span>
<h2 class="card-title h5 mt-2">Teclado mecánico</h2>
<p class="card-text text-secondary">Teclado mecánico retroiluminado</p>
<div class="d-flex justify-content-between align-items-center">
<strong class="fs-4">79,90 €</strong>
<a class="btn btn-primary" href="#">Añadir</a>
</div>
</div>
</article>
Fíjate en que Bootstrap también tiene utilidades (d-flex, mt-2, fs-4), pero como complemento de sus componentes. La diferencia con Tailwind no es que uno tenga utilidades y el otro no, sino cuál es el punto de partida: en Bootstrap partes de card y btn, ya diseñados; en Tailwind partes de cero.
Es la opción más rápida para una interfaz funcional, en especial para herramientas internas donde la apariencia importa poco. Sus costes aparecen cuando el diseño se sale de lo previsto:
- Tienes que sobrescribir reglas de Bootstrap, o configurar sus variables, para que tu web no parezca una más hecha con Bootstrap.
- Descargas todos los componentes aunque uses dos, salvo que personalices la compilación.
- Dependes de la estructura de HTML que cada componente espera.
Si quieres estudiar Bootstrap, lo encontrarás en el Curso de HTML y CSS.
Enfoque 3: Tailwind
<article class="max-w-sm overflow-hidden rounded-xl border border-gray-200 bg-white shadow-md">
<img class="h-48 w-full object-cover" src="img/teclado.svg" alt="Teclado mecánico retroiluminado">
<div class="p-5">
<span class="inline-block rounded-full bg-indigo-100 px-2.5 py-0.5 text-xs font-semibold text-indigo-800">Periféricos</span>
<h2 class="mt-3 text-xl font-bold text-gray-900">Teclado mecánico</h2>
<p class="mt-1 text-sm text-gray-600">Teclado mecánico retroiluminado</p>
<div class="mt-4 flex items-center justify-between">
<strong class="text-2xl font-bold text-gray-900">79,90 €</strong>
<a class="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white hover:bg-indigo-700" href="#">Añadir</a>
</div>
</div>
</article>
Son casi las mismas declaraciones del CSS semántico, pero escritas en otro sitio. rounded-xl es border-radius: 0.75rem, p-5 es padding: 1.25rem, y así con todas. Lo que cambia no es qué se escribe, sino dónde.

Figura 3. Las tres tarjetas reales. Bootstrap impone sus azules y su sombra; las otras dos se han escrito a medida.
Si comparas el botón de la primera y la tercera columna, el añil no es idéntico. La primera usa los valores hexadecimales de la paleta de la v3 y la tercera la paleta oklch de la v4, un poco más saturada. Lo verás en la sección 4.
Los números de la comparación
Estas son las hojas de estilos reales que recibe el navegador para mostrar esa tarjeta, medidas con estas versiones:
| Enfoque | Tamaño del CSS | Comprimido con gzip | Observación |
|---|---|---|---|
| CSS semántico (sin minificar) | 1,3 KiB | 0,5 KiB | Sin reinicio de estilos, solo esta tarjeta |
| Bootstrap 5.3.8 minificado | 226,7 KiB | 30,1 KiB | Es igual uses lo que uses |
| Tailwind 3.4.19 minificado | 5,4 KiB | 1,9 KiB | Incluye su reinicio de estilos |
| Tailwind 4.3.3 minificado | 8,6 KiB | 2,5 KiB | Incluye reinicio y variables del tema |
Tres lecturas de la tabla:
- Tailwind solo envía lo que usas. Por eso su hoja es 26 veces menor que la de Bootstrap en esta página de ejemplo. No es un milagro: es que Bootstrap incluye decenas de componentes que aquí no aparecen.
- Para una sola tarjeta gana el CSS escrito a mano. Sería engañoso decir lo contrario. La ventaja de Tailwind se nota en un proyecto grande, no en un componente aislado.
- La v4 pesa algo más que la v3 en una página tan pequeña, porque incluye las variables del tema y las declaraciones
@propertyque verás en la sección 4.
Lo interesante es cómo crece cada uno. Al añadir una pantalla nueva, el CSS semántico suma reglas nuevas, pero Tailwind reutiliza las que ya existen, porque p-5 solo se genera una vez aunque aparezca en mil elementos. Para comprobarlo se han generado 500 páginas con 40 elementos cada una, es decir, 20 000 elementos con clases variadas. El CSS resultante, sin minificar, ocupa 31,6 KiB en la v4.3.3. Multiplicar por miles el número de elementos no multiplica el CSS por miles, porque esos elementos repiten un conjunto limitado de clases.
💡 Consejo: Desconfía de cualquier comparación de tamaños que no diga qué se ha medido. La cifra útil es la de tu proyecto, y en el ejercicio 8 aprenderás a obtenerla.
¿No es lo mismo que el atributo style?
Es la objeción más frecuente al ver Tailwind por primera vez, y merece una respuesta completa. Las clases de utilidad se parecen a style="...", pero se diferencian en casi todo lo importante:
| Necesidad | style="..." | Utilidades de Tailwind |
|---|---|---|
Estado :hover o :focus | Imposible | hover:bg-indigo-700 |
| Media queries | Imposible | md:flex |
| Modo oscuro | Imposible | dark:bg-gray-800 |
| Pseudoelementos | Imposible | before:content-['*'] |
| Valores coherentes | Cualquier número | Una escala cerrada: p-4, p-5, p-6… |
| Peso de la página | Se repite en cada elemento | Una regla por clase, compartida |
| Especificidad | Máxima: gana a casi todo | La de una clase: se puede sobrescribir |
| Cambiar el tema | Buscar y sustituir | Se cambia en un solo sitio |
La fila de los valores coherentes es la más olvidada. Con style cada desarrollador elige un número. Con Tailwind eliges de una escala, así que el diseño sale coherente casi sin esfuerzo: es lo que el módulo 20 llamará diseño con restricciones.
La misma tarjeta, adaptable y con modo oscuro
Aquí es donde se ve la ventaja de las variantes. Vamos a hacer tres cosas sin salir del HTML: colocar la imagen a la izquierda en pantallas medianas, dar soporte al modo oscuro y mostrar un indicador de foco para el teclado.
<body class="bg-gray-100 p-6 dark:bg-gray-900">
<article class="mx-auto max-w-sm overflow-hidden rounded-xl border border-gray-200 bg-white shadow-md
md:flex md:max-w-2xl dark:border-gray-700 dark:bg-gray-800">
<img class="h-48 w-full bg-white object-contain p-3 md:h-auto md:w-56" src="img/teclado.svg" alt="Teclado mecánico retroiluminado">
<div class="p-5 md:flex-1">
<span class="inline-block rounded-full bg-indigo-100 px-2.5 py-0.5 text-xs font-semibold text-indigo-800
dark:bg-indigo-900 dark:text-indigo-200">Periféricos</span>
<h2 class="mt-3 text-xl font-bold text-gray-900 dark:text-white">Teclado mecánico</h2>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-300">Teclado mecánico retroiluminado</p>
<div class="mt-4 flex items-center justify-between">
<strong class="text-2xl font-bold text-gray-900 dark:text-white">79,90 €</strong>
<a class="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white hover:bg-indigo-700
focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" href="#">Añadir</a>
</div>
</div>
</article>
</body>

Figura 4. Con 800 px de ancho se aplica md:flex: imagen a la izquierda y texto a la derecha.

Figura 5. Con 420 px de ancho no se aplica ninguna clase md:, y la tarjeta queda en vertical.

Figura 6. Con el sistema operativo en modo oscuro actúan las clases dark:. No hay que cambiar nada más.
Estas tres figuras salen del mismo HTML. En CSS semántico habrías añadido a tu hoja dos bloques @media y varias reglas nuevas, con sus selectores repetidos. A cambio, ya ves el precio: el marcado es largo. Esa es la negociación central de Tailwind, y la sección 6 la trata de frente.
Estudiarás estas variantes en el módulo 10 (responsive) y el módulo 12 (modo oscuro).
4. Cómo se genera el CSS
Tailwind no sirve un fichero enorme con todas las clases posibles. Sería imposible: contando colores, tamaños y variantes combinadas hay una cantidad prácticamente infinita. En su lugar, lee tus ficheros y genera solo lo que encuentra.
Figura 7. El camino de una clase hasta el CSS final.
Los pasos son estos:
- El escáner recorre tus ficheros como texto plano. No entiende HTML, ni JavaScript, ni ejecuta nada: busca cadenas que podrían ser clases.
- El compilador comprueba cada candidata. Si
p-5es una utilidad válida, genera su regla. Siholano lo es, la ignora sin dar error. - El resultado es un CSS que contiene únicamente lo necesario, más el reinicio de estilos y lo que hayas configurado.
Ese reinicio de estilos se llama Preflight, y quita los márgenes de los encabezados, las viñetas de las listas y otros estilos por defecto del navegador. Por eso un <h1> sin clases parece texto normal en Tailwind. Lo verás a fondo en el módulo 02.
El escáner lee texto, no ejecuta código
Esta idea explica uno de los errores más comunes entre quienes empiezan. Mira este fichero y piensa qué clases se generarán:
// El escaner tambien lee los comentarios: bg-sky-300
const color = 'red';
const mal = `bg-${color}-500`;
const bien = color === 'red' ? 'bg-red-600' : 'bg-green-600';
Compilando este fichero con la CLI de la versión 4.3.3, la hoja resultante contiene estas tres reglas de fondo:
.bg-green-600
.bg-red-600
.bg-sky-300
Dos detalles importantes:
bg-red-500no aparece. En tu código nunca está escrita esa cadena: existe solo cuando el programa se ejecuta, y el escáner no ejecuta nada. Por eso esa tarjeta se vería sin fondo y sin ningún mensaje de error.bg-sky-300sí aparece, aunque esté en un comentario. Al escáner le da igual: si parece una clase, se genera.
⚠️ Importante: Escribe siempre las clases completas en tu código. Nunca las construyas uniendo trozos como
bg-${color}-500. El módulo 18 explica este problema a fondo y las alternativas en React y Angular.
Qué genera una clase: v3 frente a v4 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4) las clases generan valores directos, como
rgb(79 70 229)o0.5rem, sin variables del tema, y v4 las genera convar(--color-*)yoklch(). Si usas la LTS: las clases se escriben igual, pero si necesitas el valor de un color en tu CSS usatheme('colors.indigo.600'), porque las variables--color-*no existen.
Una misma clase produce CSS distinto en cada versión. Esta es la salida real de los compiladores para cuatro clases:
/* Tailwind 3.4.19 */
.rounded-lg {
border-radius: 0.5rem
}
.bg-indigo-600 {
--tw-bg-opacity: 1;
background-color: rgb(79 70 229 / var(--tw-bg-opacity, 1))
}
.hover\:bg-indigo-700:hover {
--tw-bg-opacity: 1;
background-color: rgb(67 56 202 / var(--tw-bg-opacity, 1))
}
@media (min-width: 768px) {
.md\:flex {
display: flex
}
}
/* Tailwind 4.3.3 */
:root, :host {
--color-indigo-600: oklch(51.1% 0.262 276.966);
--color-indigo-700: oklch(45.7% 0.24 277.023);
--radius-lg: 0.5rem;
}
.rounded-lg {
border-radius: var(--radius-lg);
}
.bg-indigo-600 {
background-color: var(--color-indigo-600);
}
@media (hover: hover) {
.hover\:bg-indigo-700:hover {
background-color: var(--color-indigo-700);
}
}
@media (width >= 48rem) {
.md\:flex {
display: flex;
}
}
Merece la pena pararse en las diferencias, porque resumen la filosofía de la v4:
| Aspecto | v3.4 | v4.3 |
|---|---|---|
| Valores del tema | Escritos dentro de cada regla | Variables CSS en :root |
| Color | rgb() | oklch(), con un rango de colores más amplio |
hover: | Siempre | Solo con @media (hover: hover), para que no se quede pegado en pantallas táctiles |
| Media query | min-width: 768px | width >= 48rem, sintaxis moderna de rangos |
Opacidad /50 | Variable --tw-bg-opacity | color-mix() |
Como las variables del tema existen de verdad en el navegador, puedes usarlas desde tu propio CSS o cambiarlas con JavaScript. Y la v4 aprovecha CSS moderno en lugar de simularlo, lo cual explica sus requisitos de navegador (sección 7).
5. Historia del proyecto
Conocer de dónde viene Tailwind ayuda a entender por qué se parece tan poco a lo que había antes.
Figura 8. Versiones principales, con las fechas de publicación en npm.
| Versión | Publicación | Qué aportó |
|---|---|---|
| 0.1 | Noviembre de 2017 | Primera versión pública, creada por Adam Wathan junto a Jonathan Reinink, David Hemphill y Steve Schoger |
| 1.0 | Mayo de 2019 | Primera versión estable |
| 2.0 | Noviembre de 2020 | Modo oscuro integrado y paleta ampliada |
| 2.1 | Abril de 2021 | Motor JIT (Just-In-Time) opcional |
| 3.0 | Diciembre de 2021 | El motor JIT pasa a ser el único |
| 3.4 | Diciembre de 2023 | Última línea de la v3, que recibe la etiqueta v3-lts |
| 4.0 | Enero de 2025 | Oxide, configuración en CSS, variables del tema |
| 4.1 | Abril de 2025 | Sombras de texto, máscaras |
| 4.2 | Febrero de 2026 | Paletas nuevas, más propiedades lógicas |
| 4.3 | Mayo de 2026 | Barras de desplazamiento, @container-size, zoom-* |
| 4.3.3 | Julio de 2026 | Versión que usa este curso |
Del fichero gigante al motor JIT
En sus primeras versiones, Tailwind hacía lo contrario de lo que has visto en la sección 4: generaba todas las combinaciones posibles en un fichero de varios megabytes, y después una herramienta eliminaba lo que no se usaba. Eso obligaba a limitar qué variantes estaban activas, porque cada una multiplicaba el tamaño, y hacía que el desarrollo fuese lento.
El motor JIT de la versión 2.1 dio la vuelta al proceso: primero lee tus ficheros y solo entonces genera lo que encuentra. Esto trajo los valores arbitrarios, como mt-[13px], porque por fin era posible generar cualquier valor al vuelo. Desde la 3.0 es la única forma de trabajar.
Oxide: la reescritura de la v4 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4) todo el procesado es JavaScript sobre PostCSS y la configuración vive en
tailwind.config.js. Si usas la LTS: instalatailwindcss@v3-lts,postcssyautoprefixer; las clases se escriben igual y solo cambia la forma de configurar y compilar, como explica el módulo 01.
La v4 reorganiza las piezas para aprovechar dos cosas: lenguajes más rápidos y un CSS nativo mucho más capaz.
Figura 9. Las piezas por dentro en cada versión.
| Pieza | v3.4 | v4.3 |
|---|---|---|
| Configuración | tailwind.config.js | Directamente en el CSS, con @theme |
| Detección de ficheros | Lista content obligatoria | Automática |
| Escáner de clases | JavaScript | Nativo en Rust (paquete @tailwindcss/oxide) |
| Prefijos y sintaxis moderna | autoprefixer, instalado aparte | Lightning CSS, incluido |
| Importar otros CSS | postcss-import, instalado aparte | Incluido |
Lo que suele contarse como “Tailwind reescrito en Rust” conviene matizarlo. Si miras dentro de node_modules, el paquete @tailwindcss/oxide es un binario nativo para tu sistema (por ejemplo @tailwindcss/oxide-win32-x64-msvc), pero el compilador principal, el paquete tailwindcss, sigue siendo JavaScript. Las partes más costosas de ejecutar son nativas, no todo.
El equipo de Tailwind publicó estas cifras al lanzar la 4.0, midiendo su plantilla Catalyst:
| Operación | v3.4 | v4.0 | Mejora |
|---|---|---|---|
| Compilación completa | 378 ms | 100 ms | 3,78 veces |
| Recompilación incremental con CSS nuevo | 44 ms | 5 ms | 8,8 veces |
| Recompilación incremental sin CSS nuevo | 35 ms | 192 µs | 182 veces |
Son cifras oficiales sobre un proyecto concreto. En una práctica de clase no vas a notar la diferencia: la verdadera ganancia aparece en proyectos grandes con el servidor de desarrollo en marcha, recompilando cada vez que guardas.
6. Ventajas y críticas
Tailwind genera debates apasionados. Tú necesitas criterio, no bando, así que aquí van las dos caras.
Ventajas reales
| Ventaja | Por qué ocurre |
|---|---|
| Desarrollo rápido | No cambias de fichero ni inventas nombres |
| CSS final pequeño | Solo se genera lo que usas, y se reutiliza |
| Diseño coherente | Espacios, colores y tamaños salen de escalas cerradas |
| Cambios seguros | Una clase afecta a su elemento y a nada más |
| Borrar es fácil | Al eliminar el HTML, sus estilos desaparecen de la siguiente compilación |
| Sin conflictos de nombres | No hay dos .tarjeta distintas en dos módulos |
| Estados y responsive en línea | hover:, md: y dark: en el mismo sitio que el resto |
| Encaja con componentes | En React o Angular el componente ya encapsula la repetición |
La ventaja de los cambios seguros es la que más se aprecia en proyectos largos. En CSS semántico, tocar .producto__nombre puede afectar a pantallas que no conoces. Cambiar text-xl por text-2xl en un elemento solo afecta a ese elemento.
Críticas, y qué hay de cierto
| Crítica | ¿Es cierta? | Qué hacer |
|---|---|---|
| “El HTML queda feo y largo” | Sí. Es su mayor coste | Componentes, y ordenar las clases con Prettier (módulo 01) |
| “Es estilo en línea” | No: ver la sección 3 | Las variantes y las escalas marcan la diferencia |
| “Se repiten las clases” | Sí, si copias y pegas | Extrae componentes o bucles de plantilla (módulo 16) |
| “Hay que aprenderse otro vocabulario” | Sí, pero es regular y se aprende en días | La extensión de VS Code autocompleta y enseña el CSS |
| “Si no sabes CSS, no entiendes nada” | Sí | Aprende CSS antes. Este curso enseña siempre el CSS generado |
| “Mezcla contenido y presentación” | En parte | El HTML sigue siendo semántico en sus etiquetas; lo que cambia son las clases |
| “Obliga a compilar” | Sí, en producción | Cualquier proyecto moderno ya tiene ese paso |
| “Cada versión renombra clases” | Lo hizo la v4 | npx @tailwindcss/upgrade y el módulo 19 |
| “Las clases se pisan” | Sí, puede pasar | tailwind-merge y buena estructura (módulo 16) |
La última crítica merece un ejemplo porque sorprende a casi todo el mundo:
<div class="p-2 p-8">¿Qué relleno tiene?</div>
Podrías pensar que gana p-8 por estar más a la derecha, pero el orden en el atributo class no significa nada para CSS. Ambas reglas tienen la misma especificidad, así que gana la que aparezca más tarde en la hoja de estilos, y ese orden lo decide Tailwind, no tú. Nunca pongas dos clases que se contradigan esperando que gane la última. Lo verás en el módulo 02.
También existe un mal hábito que conviene señalar pronto: llenar el CSS de @apply para “limpiar” el HTML. Eso recupera los costes del CSS semántico y pierde las ventajas de Tailwind. El propio equipo de Tailwind lo desaconseja como norma general. El módulo 16 explica cuándo sí tiene sentido.
Cuándo Tailwind no es la mejor opción
- Documentos con mucho contenido escrito por personas, como artículos que llegan desde un CMS: no puedes poner clases en cada
<p>. Hay solución (el plugin@tailwindcss/typography, en el módulo 04), pero ya no es utility-first. - HTML que no controlas, por ejemplo el generado por un programa de terceros.
- Equipos que ya tienen un sistema de diseño en otro lenguaje, y funciona. Migrar sin motivo cuesta más de lo que aporta.
- Un prototipo interno de un día, donde los componentes hechos de Bootstrap son más rápidos todavía.
- Una página suelta sin paso de compilación, donde unas decenas de líneas de CSS son más simples.
Tabla de decisión rápida
| Situación | Buena elección |
|---|---|
| Producto con diseño propio y varias pantallas | Tailwind |
| Aplicación con componentes (React, Angular, Vue) | Tailwind |
| Panel interno que debe estar listo mañana | Bootstrap, o Tailwind con componentes ya hechos |
| Web pequeña con pocas reglas, sin herramientas | CSS semántico |
| Artículos largos desde un CMS | CSS semántico, o @tailwindcss/typography |
7. ¿Qué versión elegir?
Este curso usa Tailwind CSS 4.3.3, la versión marcada como latest en npm. Pero quizá tú, o tu centro, o tu empresa, tengáis que trabajar con la 3.4. Todo el curso está pensado para eso, y esta sección te ayuda a decidir.
Qué significa “LTS” en Tailwind
En otros proyectos, como Node.js o Angular, LTS es un compromiso formal con fechas. En Tailwind no es así. Tailwind no publica una política de soporte a largo plazo. Lo que existe es una etiqueta en npm:
npm view tailwindcss dist-tags
{
"next": "4.0.0",
"v3-lts": "3.4.19",
"latest": "4.3.3",
"insiders": "0.0.0-insiders.410a465"
}
La etiqueta v3-lts apunta a la 3.4.19, publicada el 10 de diciembre de 2025, casi un año después de salir la v4. Es decir, la rama recibió correcciones durante un tiempo, pero nadie ha prometido hasta cuándo. Además, la guía oficial de actualización recomienda quedarse en la 3.4 a quien necesite navegadores antiguos, y esa es la razón de peso para elegirla. Por comodidad, este curso llama “LTS” a esa versión.
Para instalar cada una:
npm install tailwindcss@latest # 4.3.3
npm install tailwindcss@v3-lts # 3.4.19
Los navegadores: la razón principal
La guía oficial lo dice sin rodeos: la v4 está pensada para Safari 16.4+, Chrome 111+ y Firefox 128+, depende de funciones modernas de CSS y no funcionará en navegadores anteriores. Esas tres cifras no son arbitrarias. Salen de las funciones que usa el CSS generado:
| Función de CSS | Para qué la usa Tailwind | Chrome | Safari | Firefox |
|---|---|---|---|---|
@layer | Ordenar las capas de estilos | 99 | 15.4 | 97 |
oklch() | Paleta de colores | 111 | 15.4 | 113 |
color-mix() | Opacidad como /50 | 111 | 16.2 | 113 |
@property | Variables con tipo y valor inicial | 85 | 16.4 | 128 |
La cifra más alta de cada columna da el requisito de la v4: oklch() y color-mix() fijan Chrome 111, y @property fija Safari 16.4 y Firefox 128. En la tarjeta de la sección 3, el CSS de la v4 contiene 16 reglas @property, 5 @layer, 8 oklch y 2 color-mix. El de la v3 no contiene ninguna.
📘 Concepto: Los datos de la tabla proceden de
@mdn/browser-compat-data, la base de datos de compatibilidad de MDN. Chrome 111 y Safari 16.4 son de marzo de 2023, y Firefox 128 es de julio de 2024. Para el público general suelen ser versiones ya superadas, pero no necesariamente en empresas con equipos gestionados, en tabletas antiguas o en dispositivos que dejaron de actualizarse.
Si tu proyecto ya tiene usuarios, no adivines: mira las estadísticas de navegadores de tu web, y consulta la cobertura global en caniuse.com.
Otras razones para quedarse en v3
- Sass, Less o Stylus. La v4 no está diseñada para usarse con preprocesadores, y no puedes usarlos en tus hojas de estilo junto a Tailwind. La idea es que el propio Tailwind haga de preprocesador. Si tu proyecto depende de Sass y no puedes retirarlo, quédate en la 3.4.
- Un proyecto existente sin tiempo de migración. Migrar requiere revisar pantallas, porque hay cambios silenciosos (los verás a continuación). La v3 sigue funcionando; no hay ninguna urgencia técnica.
- Plugins de v3 sin actualizar, o herramientas que dependen de
tailwind.config.js. La v4 admite cargar ese fichero con@config, pero no todo se comporta igual.
Diagrama de decisión
Figura 10. Si contestas “sí” a alguna pregunta, quédate en la 3.4.
En un proyecto nuevo, sin navegadores antiguos ni Sass, no hay motivo para empezar en la v3.
Lo que se pierde en v3 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4) no existen las funciones de la tabla de esta sección. Si usas la LTS: usa la alternativa de la columna derecha, normalmente una propiedad arbitraria entre corchetes como
[text-shadow:...], o un plugin cuando se indique.
Todas las clases de la tabla se han comprobado con los dos compiladores, y en la columna derecha está lo que sí funciona en la 3.4.19. Fíjate en que casi todo tiene alternativa: lo que pierdes en la v3 no suele ser la capacidad de hacerlo, sino la comodidad de una clase con nombre.
| Desde | Función | Clase en v4 | Alternativa en v3.4 |
|---|---|---|---|
| 4.0 | Consultas de contenedor | @container, @md:flex | Plugin @tailwindcss/container-queries |
| 4.0 | Valores dinámicos | grid-cols-15, mt-17 | grid-cols-[repeat(15,minmax(0,1fr))], mt-[4.25rem] |
| 4.0 | Gradiente lineal | bg-linear-to-r | bg-gradient-to-r |
| 4.0 | Gradiente con ángulo | bg-linear-45 | bg-[linear-gradient(45deg,...)] |
| 4.0 | Gradiente radial y cónico | bg-radial, bg-conic | bg-[radial-gradient(...)], bg-[conic-gradient(...)] |
| 4.0 | Transformaciones 3D | rotate-x-45, perspective-near | [transform:rotateX(45deg)], [perspective:300px] |
| 4.0 | Sombra y aro interiores | inset-shadow-sm, inset-ring-2 | shadow-inner (valor fijo), ring-2 ring-inset |
| 4.0 | Variante negada | not-hover:flex | [&:not(:hover)]:flex |
| 4.0 | Variante “dentro de” | in-focus:flex | group en el padre y group-focus:flex |
| 4.0 | Variante nth | nth-3:bg-red-500 | [&:nth-child(3)]:bg-red-500 |
| 4.0 | Animar la aparición | starting:opacity-0 | [@starting-style]:opacity-0 |
| 4.0 | Campos que crecen | field-sizing-content | [field-sizing:content] |
| 4.0 | Elementos inertes | inert:opacity-50 | [&[inert]]:opacity-50 |
| 4.1 | Sombra de texto | text-shadow-md | [text-shadow:0_2px_4px_rgb(0_0_0/0.5)] |
| 4.1 | Máscaras | mask-b-from-50% | [mask-image:linear-gradient(black,transparent)] |
| 4.1 | Partir palabras | wrap-break-word, wrap-anywhere | break-words, [overflow-wrap:anywhere] |
| 4.1 | Tipo de puntero | pointer-coarse:p-4 | [@media(pointer:coarse)]:p-4 |
| 4.1 | Validez tras interactuar | user-valid:border-green-500 | [&:user-valid]:border-green-500 |
| 4.1 | Alineación segura | justify-center-safe | [justify-content:safe_center] |
| 4.1 | Última línea base | items-baseline-last | [align-items:last_baseline] |
| 4.1 | Tamaño de fondo | bg-size-[auto_100px] | bg-[length:auto_100px] |
| 4.1 | Contenido de <details> | details-content:p-2 | [&::details-content]:p-2 |
| 4.1 | Sin JavaScript | noscript:block | [@media(scripting:none)]:block |
| 4.2 | Paletas nuevas | bg-mauve-500 | Define el color en theme.extend.colors |
| 4.2 | Propiedades lógicas | pbs-4, inset-s-4 | [padding-block-start:1rem], start-4 |
| 4.2 | Rasgos tipográficos | font-features-["smcp"] | [font-feature-settings:"smcp"] |
| 4.3 | Barra de desplazamiento | scrollbar-thin, scrollbar-thumb-red-500 | [scrollbar-width:thin], [scrollbar-color:red_blue] |
| 4.3 | Contenedor por tamaño | @container-size | [container-type:size] |
| 4.3 | Zoom | zoom-50 | [zoom:0.5] |
| 4.3 | Ancho del tabulador | tab-4 | [tab-size:4] |
Las alternativas funcionan en la 3.4 porque Tailwind genera lo que le pidas entre corchetes, pero ojo: que la clase compile no significa que el navegador antiguo entienda esa propiedad. [field-sizing:content] no hará nada en un navegador que no conozca field-sizing. Quedarte en la v3 por los navegadores resuelve la compatibilidad de Tailwind, no la del CSS que tú pidas.

Figura 11. El mismo HTML compilado con cada versión. Arriba, en v3, las clases nuevas no generan nada, sin avisar. El gradiente cónico ni siquiera se ve.
Observa lo que no ocurre: no hay ningún error. Una clase que Tailwind no conoce simplemente no genera CSS, tal como viste en la sección 4. Por eso conviene saber qué versión tienes delante.
Los falsos amigos 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4) varias clases con el mismo nombre tienen otro valor:
shadow-sm,rounded-sm,blur-smyring, ybordersin color es gris, nocurrentColor. Si usas la LTS: sigue los valores de v3; en cada módulo se indica el equivalente, y al copiar código de una versión a otra revisa estas clases.
Lo más peligroso de pasar de una versión a otra no son las clases que faltan, sino las que existen en las dos con distinto resultado. Mira este experimento:

Figura 12. El mismo HTML compilado con cada versión. Ninguna de estas clases da error en ninguna de las dos.
| Clase | En v3.4 | En v4.3 | Para lo mismo que en v3, en v4 usa |
|---|---|---|---|
border sin color | Gris claro | currentColor: el color del texto | Añade border-gray-200 |
ring | 3 px, azul | 1 px, currentColor | ring-3 |
shadow-sm | 0 1px 2px 0 al 5 % | Más marcada, dos capas al 10 % | shadow-xs |
rounded-sm | 0.125rem | 0.25rem | rounded-xs |
blur-sm | 4px | 8px | blur-xs |
| placeholder | Gris 400 | Color del texto al 50 % | placeholder-gray-400 |
Observa la tabla de otra forma: la escala se desplazó un puesto. Lo que en v3 era shadow-sm ahora es shadow-xs, y lo que en v3 era shadow ahora es shadow-sm. Las clases cambiaron de significado sin cambiar de nombre. Si copias código de un tutorial antiguo a un proyecto v4, compilará perfectamente y se verá un poco distinto.
La lista completa está en el módulo 19, y el módulo 06 estudia a fondo los casos de bordes y sombras.
💡 Consejo: Al buscar ejemplos en internet, comprueba la fecha. Cualquier texto anterior a 2025 habla de la v3 o de una versión más antigua. Las señales de que un ejemplo es de v3 son
@tailwind base,tailwind.config.js,bg-opacity-50ybg-gradient-to-r.
8. Cómo leer las marcas del curso
Como cada persona puede elegir su versión, cada apartado afectado lleva una marca al final del encabezado y una caja justo debajo. Hay dos marcas:
| Marca | Significado | Qué hacer si usas la 3.4 |
|---|---|---|
| 🆕 v4.1 | La función no existe en la 3.4. El número es la versión en que apareció | Lee la caja: te da la alternativa |
| 🔄 v4.0 | La función existe, pero cambia: otro nombre, otro valor u otra forma de configurarla | Lee la caja: te da el equivalente |
Las cajas siempre terminan con una frase que empieza por Si usas la LTS:, con lo que debes hacer. Si un apartado no lleva marca, funciona igual en las dos versiones.
Estos dos apartados son ejemplos reales de cómo verás las marcas en el resto del curso.
Ejemplo de novedad: sombra de texto con text-shadow-* 🆕 v4.1
🆕 Desde Tailwind 4.1. No existe en la LTS (Tailwind 3.4). Si usas la LTS: usa una propiedad arbitraria como
[text-shadow:0_2px_4px_rgb(0_0_0/0.5)], que produce el mismo efecto.
<h2 class="text-2xl font-bold text-white text-shadow-lg">Oferta</h2>
Ejemplo de cambio: la configuración con @theme 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4) el tema se configura en
tailwind.config.js. Si usas la LTS: añade el valor entheme.extend, como en el segundo bloque de este apartado; la clase resultante,bg-marca, se usa igual.
/* v4: en tu hoja de estilos */
@import "tailwindcss";
@theme {
--color-marca: #3f51b5;
}
// v3: en tailwind.config.js
module.exports = {
content: ['./**/*.html'],
theme: {
extend: {
colors: { marca: '#3f51b5' },
},
},
};
⚠️ Importante: Hay módulos que dependen mucho de la v4, como el módulo 14 o el módulo 15. Si sigues el curso con la 3.4, en esos módulos léete las cajas antes que el código.
9. Mapa del curso
Figura 13. Los módulos del curso agrupados por bloques.
| Módulo | Título | Qué aprenderás |
|---|---|---|
| 01 | Instalación y entorno | Vite, CLI, PostCSS y CDN; VS Code y Prettier; por qué una clase no aparece |
| 02 | Utilidades y Preflight | Cómo se genera el CSS, capas, escalas, valores arbitrarios |
| 03 | Espaciado y tamaño | Relleno, márgenes, anchos, alturas, propiedades lógicas |
| 04 | Tipografía | Fuentes, tamaños, truncado, plugin typography |
| 05 | Color y fondos | Paleta oklch, opacidad, gradientes |
| 06 | Bordes, sombras y efectos | border, ring, sombras, filtros, máscaras |
| 07 | Layout y posicionamiento | position, z-index, overflow, barras de desplazamiento |
| 08 | Flexbox | Toda la familia flex, con ejemplos visuales |
| 09 | CSS Grid | Rejillas, subgrid y maquetaciones completas |
| 10 | Diseño responsive | Mobile first, puntos de ruptura, consultas de contenedor |
| 11 | Variantes y estados | hover, group, peer, has, not, aria, data |
| 12 | Modo oscuro y temas | dark:, conmutador con JavaScript, temas múltiples |
| 13 | Animaciones y 3D | Transiciones, @keyframes, transformaciones 3D |
| 14 | Personalizar el tema | @theme a fondo, marca propia |
| 15 | Utilidades y plugins | @utility, @custom-variant, @plugin, @apply |
| 16 | Componentes reutilizables | Cuándo extraer, tailwind-merge, class-variance-authority |
| 17 | Formularios y tablas | Plugin forms, validación, <dialog>, tablas adaptables |
| 18 | React, Angular y otros | Integración, clases dinámicas |
| 19 | Migración de v3 a v4 | npx @tailwindcss/upgrade sobre un proyecto real |
| 20 | Producción y rendimiento | Tamaño del CSS, CSP, compatibilidad, accesibilidad |
| 21 | Proyecto final | La tienda EMPRESA completa, con panel de control |
Qué se construye
El hilo conductor del curso es una tienda de EMPRESA. Con sus datos (productos, clientes, pedidos, empleados) construirás tarjetas, tablas, formularios, navegación y un panel de control, hasta juntarlo todo en el proyecto final. Los ejemplos son HTML puro, para que veas solo Tailwind, salvo en el módulo de integración con frameworks.
Si también haces los cursos de React o Angular, te resultarán familiares estos datos, porque son los mismos que usan esos cursos.
Qué necesitas
| Requisito | Nivel |
|---|---|
| HTML y CSS | Sabes qué son el modelo de cajas, flexbox y los selectores. Si no, empieza por el Curso de HTML y CSS |
| JavaScript | Básico, para el módulo 12 y el módulo 18. Repásalo en el Curso de JavaScript |
| Node.js | Instalado a partir del módulo 01. La herramienta de migración pide la versión 20 o superior |
| Un editor | Recomendamos VS Code, con la extensión oficial de Tailwind |
Cómo sacarle partido
- Escribe las clases a mano en lugar de copiar. El vocabulario se aprende escribiéndolo.
- Abre las herramientas de desarrollo del navegador (F12) y mira qué CSS produce cada clase.
- Consulta la documentación oficial en tailwindcss.com/docs cuando dudes: el buscador es excelente.
- Pruébalo sin instalar nada en play.tailwindcss.com, el entorno de pruebas oficial en línea.
- Haz los ejercicios propuestos, no solo los resueltos.
10. Ejercicios
Salvo que se indique otra cosa, resuélvelos en un fichero HTML con el <script> del CDN de la sección 2.
Ejercicio 1: Traduce clases a CSS
Sin mirar la documentación, intenta escribir el CSS que hace este botón. Después comprueba tu respuesta en la solución.
<a class="inline-block rounded-lg bg-blue-600 px-4 py-2 text-sm font-semibold text-white">Comprar</a>
Ver solución
Este es el significado de cada clase, con los valores del tema de la 4.3.3:
.boton {
display: inline-block; /* inline-block */
border-radius: 0.5rem; /* rounded-lg */
background-color: oklch(54.6% 0.245 262.881); /* bg-blue-600 */
padding-inline: 1rem; /* px-4 */
padding-block: 0.5rem; /* py-2 */
font-size: 0.875rem; /* text-sm */
line-height: calc(1.25 / 0.875); /* text-sm */
font-weight: 600; /* font-semibold */
color: #fff; /* text-white */
}
Dos cosas que conviene observar:
pxypyusan propiedades lógicas (padding-inline,padding-block), nopadding-left. En un idioma que se escriba de derecha a izquierda seguirán funcionando.- La escala de espaciado es regular: cada unidad vale
0.25rem, de modo quepx-4es4 × 0.25rem = 1rem, ypy-2es0.5rem. Lo verás en el módulo 02.
text-sm da dos valores a la vez, tamaño y altura de línea, y por eso una sola clase resuelve lo que en CSS son dos declaraciones.
Ejercicio 2: Del CSS semántico a utilidades
Reescribe este botón solo con clases de Tailwind, sin ningún CSS propio. Debe verse igual en estado normal, al pasar el ratón y desactivado.
.boton-confirmar {
padding: 0.5rem 1rem;
border-radius: 0.375rem;
background-color: #059669;
color: #fff;
font-weight: 500;
cursor: pointer;
}
.boton-confirmar:hover {
background-color: #047857;
}
.boton-confirmar:disabled {
opacity: 0.5;
cursor: not-allowed;
}
Ver solución
<button class="cursor-pointer rounded-md bg-emerald-600 px-4 py-2 font-medium text-white
hover:bg-emerald-700 disabled:cursor-not-allowed disabled:opacity-50">
Confirmar pedido
</button>
<button disabled class="cursor-pointer rounded-md bg-emerald-600 px-4 py-2 font-medium text-white
hover:bg-emerald-700 disabled:cursor-not-allowed disabled:opacity-50">
Confirmar pedido
</button>

Figura 14. Resultado de la solución, con el botón normal y el desactivado.
Claves de la solución:
hover:ydisabled:son variantes: aplican la clase solo en ese estado, igual que:hovery:disableden CSS.cursor-pointerhace falta porque en la v4 los botones usancursor: default. En la v3, Preflight ya les dabacursor: pointer, así que allí puedes omitirla.- Los colores no son exactamente los hexadecimales del enunciado:
bg-emerald-600es un coloroklchmuy parecido. Si necesitas el valor exacto, puedes escribirbg-[#059669].
Ejercicio 3: De Bootstrap a Tailwind
Esta alerta de Bootstrap avisa de que queda poco stock. Reescríbela con Tailwind. El producto es real: de Torre Workstation quedan 4 unidades.
<div class="alert alert-warning" role="alert">
<h4 class="alert-heading">Stock bajo</h4>
<p class="mb-0">Quedan <strong>4 unidades</strong> de Torre Workstation.</p>
</div>
Ver solución
<div class="max-w-xl rounded-md border border-amber-300 bg-amber-100 px-4 py-3 text-amber-900" role="alert">
<h4 class="text-lg font-semibold">Stock bajo</h4>
<p class="mt-1">Quedan <strong>4 unidades</strong> de Torre Workstation.</p>
</div>

Figura 15. Alerta reconstruida con utilidades.
Observa lo que ha cambiado:
- En Bootstrap, una clase (
alert-warning) decide varios colores a la vez. Aquí se escribe cada uno, lo que da más control a cambio de más clases. - El atributo
role="alert"se queda. Tailwind solo cambia el aspecto. La accesibilidad sigue siendo responsabilidad del HTML. - El
<h4>necesitatext-lg font-semibold, porque Preflight le quitó el tamaño y el peso que trae el navegador. - Si esta alerta se repite por toda la web, habría que extraerla como componente, como verás en el módulo 16.
Ejercicio 4: Tarjeta de un pedido
Con el CDN, crea una tarjeta para el pedido 5001 de la tienda EMPRESA, con estos datos:
| Campo | Valor |
|---|---|
| Identificador | 5001 |
| Fecha del pedido | 15/01/2025 |
| Fecha de envío | 17/01/2025 |
| Estado | ENTREGADO |
Debe tener el título y el estado en una misma línea, con el estado en forma de píldora verde; las fechas debajo; y un botón “Ver detalle” a todo el ancho. Puede que necesites flex, justify-between y items-center.
Ver solución
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<title>Pedido 5001</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
</head>
<body class="bg-slate-100 p-8">
<article class="mx-auto max-w-md rounded-xl bg-white p-6 shadow-md">
<header class="flex items-center justify-between">
<h1 class="text-lg font-bold text-gray-900">Pedido 5001</h1>
<span class="rounded-full bg-emerald-100 px-3 py-1 text-xs font-semibold text-emerald-800">ENTREGADO</span>
</header>
<dl class="mt-4 space-y-2 text-sm">
<div class="flex justify-between">
<dt class="text-gray-500">Fecha del pedido</dt>
<dd class="font-medium text-gray-900">15/01/2025</dd>
</div>
<div class="flex justify-between">
<dt class="text-gray-500">Fecha de envío</dt>
<dd class="font-medium text-gray-900">17/01/2025</dd>
</div>
</dl>
<a class="mt-6 block rounded-lg border border-gray-300 py-2 text-center text-sm font-semibold text-gray-700 hover:bg-gray-50" href="#">
Ver detalle
</a>
</article>
</body>
</html>

Figura 16. Tarjeta del pedido 5001.
Puntos importantes:
- Se usa una lista de definiciones (
<dl>,<dt>,<dd>), porque son pares de nombre y valor. Las clases no eximen de elegir bien las etiquetas. space-y-2separa los hijos del<dl>sin poner márgenes en cada uno.border-gray-300es necesaria en la v4, porque el color del borde sería el del texto,currentColor. Es uno de los falsos amigos de la sección 7.blockhace que el enlace ocupe toda la anchura.
Ejercicio 5: Elige versión
Para cada caso, decide entre Tailwind 4.3 y Tailwind 3.4, y justifica tu respuesta.
- Una academia crea desde cero una web para sus cursos. Sus estadísticas de otras webs muestran navegadores actualizados.
- Una empresa tiene una intranet que debe funcionar en quioscos con Chrome 96, que no se van a actualizar.
- Un proyecto en v3 lleva cuatro años en producción, con 200 pantallas y Sass en todos sus componentes.
- Una aplicación React en v3 con 15 pantallas, sin Sass, y con navegadores modernos. El equipo tiene una semana libre.
- Una tienda en línea dirigida al público general quiere usar
text-shadow-*ymask-*, y duda si aporta riesgo.
Ver solución
- 4.3. Es un proyecto nuevo, sin restricciones: no hay razón para empezar en la 3.4.
- 3.4. Chrome 96 es anterior a Chrome 111, y además no conoce
@layer(Chrome 99). Con la v4 la página quedaría rota o sin estilos, tal como advierte la guía oficial. - 3.4, al menos de momento. Tiene dos motivos a la vez: Sass, que no se puede usar con la v4, y el coste de revisar 200 pantallas. Si en el futuro se retira Sass, se puede plantear la migración.
- 4.3. Una semana basta para un proyecto de ese tamaño, sin Sass y con navegadores modernos. La herramienta
npx @tailwindcss/upgradehace gran parte del trabajo, y después hay que revisar visualmente los falsos amigos. - 4.3, revisando sus usuarios. Las máscaras y las sombras de texto no exigen nada que no exija ya la v4. La decisión real depende de los navegadores de sus clientes, que debe comprobar en sus estadísticas. Una tienda puede tener usuarios con móviles antiguos, y por eso la métrica importa más que la intuición.
Ejercicio 6: ¿Existe esa clase?
Clasifica estas clases según existan en la 3.4.19, en la 4.3.3 o en ambas: bg-opacity-50, shadow-xs, outline-hidden, size-10, grid-cols-15, start-4, flex-shrink-0, bg-gradient-to-r, bg-linear-to-r, backdrop-blur-xs.
Si ya has hecho el módulo 01, puedes comprobarlo tú mismo: compila un HTML con esas clases con cada versión y busca en el CSS qué se ha generado.
Ver solución
Resultado real de compilar cada clase con los dos compiladores:
| Clase | 3.4.19 | 4.3.3 | Comentario |
|---|---|---|---|
bg-opacity-50 | Sí | No | Eliminada. En v4 se escribe bg-black/50 |
shadow-xs | No | Sí | Renombrada en v4 |
outline-hidden | No | Sí | Equivale al outline-none de v3 |
size-10 | Sí | Sí | Añadida en la 3.4 |
grid-cols-15 | No | Sí | Valores dinámicos de v4 |
start-4 | Sí | Sí | Sigue funcionando, pero está obsoleta desde la 4.2 |
flex-shrink-0 | Sí | Sí | Ver la nota |
bg-gradient-to-r | Sí | Sí | Sigue funcionando, aunque el nombre actual es bg-linear-to-r |
bg-linear-to-r | No | Sí | Nombre nuevo |
backdrop-blur-xs | No | Sí | Escala desplazada |
Nota sobre flex-shrink-0: la guía oficial la da por eliminada a favor de shrink-0, pero la 4.3.3 sigue generándola, con flex-shrink: 0. No te fíes de que siga ahí en futuras versiones: usa shrink-0 y grow, que funcionan en ambas.
La lección es que “existe” no equivale a “es correcto”. Una clase puede estar por compatibilidad, y otra puede tener un valor distinto.
Ejercicio 7: Cazar falsos amigos
Has copiado esta tarjeta de un proyecto en 3.4 a uno en 4.3. Compila sin errores, pero se ve distinta. Reescríbela para que tenga en v4 exactamente los mismos valores que en v3.
<div class="rounded-sm border p-4 shadow-sm ring">
<img class="blur-sm" src="img/teclado.svg" alt="">
</div>
Ver solución
<div class="rounded-xs border border-gray-200 p-4 shadow-xs ring-3 ring-blue-500/50">
<img class="blur-xs" src="img/teclado.svg" alt="">
</div>
| En v3 | Valor en v3 | Mismo valor en v4 |
|---|---|---|
rounded-sm | 0.125rem | rounded-xs |
border | Gris 200 | border border-gray-200 |
shadow-sm | 0 1px 2px 0 rgb(0 0 0 / 0.05) | shadow-xs |
ring | 3 px en azul al 50 % | ring-3 ring-blue-500/50 |
blur-sm | 4px | blur-xs |
El color de ring-blue-500/50 se acerca mucho, pero no es idéntico: la paleta de la v4 está definida en oklch.
No olvides que estos cambios no los detecta ningún compilador. Se notan solo mirando la pantalla, o usando npx @tailwindcss/upgrade, que renombra las clases por ti, como verás en el módulo 19.
Ejercicio 8: Mide tu CSS
Comprueba tú mismo cómo crece el CSS generado. Necesitarás Node.js, que instalarás en el módulo 01 si aún no lo tienes.
- Crea una carpeta con tu
primera.html, quitándole el<script>del CDN. - Crea
entrada.csscon este contenido:
@import "tailwindcss";
- Compila con la CLI y anota el tamaño de
salida.css:
npm install tailwindcss @tailwindcss/cli
npx @tailwindcss/cli -i entrada.css -o salida.css --minify
- Cambia
text-indigo-700portext-rose-700, compila y anota. - Añade
ring-2 md:px-8al botón, compila y anota.
Explica los tres resultados.
Ver solución
Estos son los resultados en el laboratorio del curso con la 4.3.3:
| Paso | Bytes | Diferencia |
|---|---|---|
| Página inicial | 7 549 | |
Cambiar text-indigo-700 por text-rose-700 | 7 587 | +38 |
Añadir ring-2 md:px-8 | 7 924 | +337 |
Se explica así:
- Punto de partida. Una página tan simple pesa unos 7,5 KB porque casi todo es Preflight y las variables que usa. Por eso medir una sola página da una impresión falsa.
- Cambio de color.
text-indigo-700desaparece, perotext-rose-700y su variable entran. Comoindigo-700lo sigue necesitandohover:bg-indigo-700, su variable sigue ahí y por eso el tamaño crece un poco. - Clases nuevas.
ring-2no es tan pequeña como parece: arrastra las variables de sombra y aro y sus declaraciones@property.md:px-8añade la media query.
Tu cifra puede variar en unos bytes, porque si dejas otros ficheros en la carpeta el escáner también los leerá. Esa es, de hecho, una lección: compila desde una carpeta con solo lo necesario, o aprende a usar @source en el módulo 01.
Ejercicio 9: ¿Por qué no sale el color?
Un compañero escribe este código y dice que “Tailwind no funciona”, porque ningún estado muestra su color de fondo. Explícale el fallo y corrígelo, sin añadir nada a la configuración.
const estados = { ENTREGADO: 'green', ENVIADO: 'blue', PENDIENTE: 'amber' };
function clasesEstado(estado) {
return `rounded-full px-3 py-1 text-xs bg-${estados[estado]}-100`;
}
Ver solución
El escáner lee el fichero como texto y solo encuentra el trozo bg-${estados[estado]}-100, que no es una clase. Nunca ve bg-green-100, así que nunca genera su CSS. La clase llega correctamente al HTML, y por eso el error confunde tanto: si lo inspeccionas en el navegador, la clase está, pero no hay ninguna regla CSS para ella.
La solución es escribir cada clase entera en el código:
const estados = {
ENTREGADO: 'bg-green-100',
ENVIADO: 'bg-blue-100',
PENDIENTE: 'bg-amber-100',
};
function clasesEstado(estado) {
return `rounded-full px-3 py-1 text-xs ${estados[estado]}`;
}
Ahora las tres cadenas completas están en el fichero, y el escáner las encuentra aunque estén en un objeto de JavaScript, porque solo le importa que aparezca el texto. Como viste en la sección 4, tampoco importa dónde.
Hay más alternativas, como @source inline(), en el módulo 18.
Ejercicio 10 (propuesto): La barra de navegación en tres versiones
Construye la barra de navegación de la tienda EMPRESA, con logotipo a la izquierda y tres enlaces a la derecha, de las tres formas de la sección 3: CSS semántico, Bootstrap y Tailwind. Anota cuántas líneas has escrito en cada caso, cuántas clases has inventado y qué cambio te ha costado menos: añadir un cuarto enlace o cambiar el color de fondo.
Ejercicio 11 (propuesto): Investiga los navegadores de tu público
Elige una web que conozcas, propia o de tu centro. Si tienes acceso a sus estadísticas, averigua qué porcentaje de visitas usa navegadores por debajo de Safari 16.4, Chrome 111 o Firefox 128. Si no, consulta en caniuse.com la cobertura global de @property y de color-mix(). Redacta en cinco líneas qué versión de Tailwind recomendarías y por qué.
Ejercicio 12 (propuesto): Inspecciona una web real
Abre tailwindcss.com con las herramientas de desarrollo del navegador. Selecciona un botón y anota sus clases. Elige cinco clases que no conozcas y deduce qué hacen a partir del panel de estilos. Busca también en el panel de estilos alguna variable --color-* y, si te atreves, cámbiale el valor desde el navegador para ver el efecto.
Resumen
| Concepto | API | Idea clave |
|---|---|---|
| Utilidad | p-4, text-sm, bg-white | Clase pequeña con una sola tarea |
| Utility-first | Combinar clases en el HTML | El estilo vive en el marcado, no en otro fichero |
| Variante | hover:, md:, dark: | Aplica una clase solo en un estado o contexto |
| CDN de desarrollo | @tailwindcss/browser | Solo para probar, nunca en producción |
| CSS semántico | .producto__boton | HTML limpio, a cambio de nombres y CSS creciente |
| Bootstrap | card, btn btn-primary | Componentes hechos, a cambio de salirse poco de ellos |
| Escáner | Lee texto plano | No ejecuta nada: bg-${color}-500 no se genera |
| Preflight | Reinicio de estilos | Quita los estilos por defecto del navegador |
| Motor JIT | Desde 2.1, único desde 3.0 | Genera solo lo que aparece en tus ficheros |
| Oxide | @tailwindcss/oxide | Escáner nativo en Rust, con compilador en JavaScript |
| Lightning CSS | Incluido en v4 | Prefijos y sintaxis moderna, sin autoprefixer |
| Requisitos de v4 | Safari 16.4+, Chrome 111+, Firefox 128+ | Por @property, color-mix() y oklch() |
| Preprocesadores | Sass, Less, Stylus | No se pueden usar con v4 |
| “LTS” | Etiqueta npm v3-lts | No hay política formal: es la 3.4.19 |
| Alternativa en v3 | [text-shadow:...] | Una propiedad arbitraria cubre casi todo lo que falta |
| Falsos amigos | shadow-sm, rounded-sm, blur-sm, ring, border | Mismo nombre y otro resultado, sin ningún error |
| Marca 🆕 | 🆕 v4.1 | No existe en la 3.4 |
| Marca 🔄 | 🔄 v4.0 | Existe, pero cambia |
| Migración | npx @tailwindcss/upgrade | Requiere Node 20+ y ver el módulo 19 |
| Navegación | |
|---|---|
| Siguiente módulo: Instalación y entorno → |