Módulo 05: Color y fondos
Objetivos del módulo
- Leer cualquier clase de color separando propiedad, familia, paso y opacidad
- Conocer la paleta por defecto y elegir pasos con criterio, incluido el contraste
- Entender qué significan los tres números de
oklch()y por qué Tailwind cambió de formato - Saber que
bg-red-500no es el mismo rojo en v3 y en v4 - Aplicar opacidad con
/50, distinguirla deopacity-50y saber qué CSS produce - Aprovechar
currentColorpara construir componentes que cambian de color con una sola clase - Usar variables y valores arbitrarios en fondos con la sintaxis correcta
- Construir degradados lineales, radiales y cónicos con
from-*,via-*yto-* - Elegir el espacio de interpolación de un degradado para evitar los tonos grises del centro
- Colocar imágenes de fondo con
bg-cover,bg-center,bg-size-*ybg-repeat-* - Combinar imagen y degradado sin que una clase anule a la otra
- Rellenar texto con un degradado usando
bg-clip-text - Mezclar colores con
color-mix()y derivar una paleta propia - Personalizar controles de formulario con
accent-*ycaret-*, y conocer sus límites
1. Preparación del laboratorio
Sigues con el proyecto Vite del módulo 01. Bastan un index.html y un app.css con esta línea:
@import "tailwindcss";
Algunos ejemplos usan dos imágenes. Guárdalas en la carpeta public/img/ de tu proyecto:
| Descarga | Guárdala como | Para qué sirve |
|---|---|---|
| 05-img-escena.svg | public/img/escena.svg | Fotografía de ejemplo, de 600 × 300 px |
| 05-img-motivo.svg | public/img/motivo.svg | Baldosa de 40 × 40 px que se repite |
Vite sirve el contenido de public/ desde la raíz, de modo que la ruta en el HTML es /img/escena.svg.
⚠️ Importante: Vite no detecta siempre los HTML creados con el servidor en marcha. Si una clase nueva no aparece, guarda
app.csssin cambiar nada para que Tailwind vuelva a escanear.
Los ejemplos también usan clases que todavía no has estudiado o que ya viste:
| Clases | Qué hacen | Dónde se estudian |
|---|---|---|
p-4, mt-2, w-64, size-40, w-fit | Relleno, margen y tamaño | Espaciado y tamaño |
text-sm, font-bold, text-4xl | Texto | Tipografía |
border, rounded-lg | Bordes y esquinas | Bordes, sombras y efectos |
relative, absolute, inset-0 | Posicionamiento | Layout y posicionamiento |
flex, grid, gap-4, items-center | Colocación | Flexbox y Grid |
hover:, dark: | Aplican una clase en una condición | Variantes y estados y Modo oscuro |
Si quieres repasar los fondos en CSS puro, tienes el Curso de HTML y CSS.
2. Cómo se nombra un color
Toda clase de color sigue la misma receta: qué se pinta, qué color y, si hace falta, cuánta opacidad.
Figura 1. Las partes de una clase de color. Solo cambia el prefijo de la propiedad.
Esto significa que, cuando aprendes la paleta, ya sabes usarla en todas partes:
| Prefijo | Propiedad CSS | Ejemplo | Dónde se detalla |
|---|---|---|---|
bg- | background-color | bg-indigo-600 | Este módulo |
text- | color | text-gray-900 | Este módulo |
from-, via-, to- | Paradas de un degradado | from-rose-500 | Este módulo |
accent- | accent-color | accent-indigo-600 | Este módulo |
caret- | caret-color | caret-rose-500 | Este módulo |
fill-, stroke- | fill, stroke en SVG | fill-current | Este módulo |
decoration- | text-decoration-color | decoration-red-500 | Tipografía |
border-, divide- | border-color | border-gray-200 | Módulo 06 |
ring-, outline- | Anillo y contorno | ring-indigo-500 | Módulo 06 |
shadow- | Color de la sombra | shadow-indigo-500/50 | Módulo 06 |
Las clases funcionan porque el tema define variables CSS. Cuando usas bg-indigo-600, Tailwind genera dos cosas:
:root, :host {
--color-indigo-600: oklch(51.1% 0.262 276.966);
}
.bg-indigo-600 {
background-color: var(--color-indigo-600);
}
Y como es una variable normal, puedes leerla en tu propio CSS o dentro de un valor arbitrario: var(--color-indigo-600). Solo llegan a la hoja final las variables que se usan, como viste en el módulo 02. Para crear tus colores con @theme, sigue leyendo: la sección 15 da un ejemplo y el módulo 14 lo trata a fondo.
3. La paleta por defecto
Tailwind 4.3 incluye 26 familias de color, cada una con 11 pasos: 286 tonos listos para usar. La tabla la ha generado el propio laboratorio con bg-* reales.

Figura 2. Las 26 familias de Tailwind 4.3. Las nueve inferiores son grises con matices distintos.
| Grupo | Familias |
|---|---|
| Rojos y naranjas | red, orange, amber, yellow |
| Verdes | lime, green, emerald, teal |
| Azules | cyan, sky, blue, indigo |
| Morados y rosas | violet, purple, fuchsia, pink, rose |
| Grises fríos | slate, gray, zinc |
| Grises neutros y cálidos | neutral, stone |
| Grises con matiz (4.2) | taupe, mauve, mist, olive (sección 14) |
Además hay valores sueltos que no pertenecen a ninguna familia:
| Clase | CSS | Uso |
|---|---|---|
bg-white, bg-black | var(--color-white), var(--color-black) | #fff y #000 |
bg-transparent | transparent | Quitar un fondo, por ejemplo en hover: |
bg-current | currentcolor | Tomar el color del texto (sección 6) |
bg-inherit | inherit | Heredar el fondo del padre |
Cómo elegir el paso
Los pasos van del 50, casi blanco, al 950, casi negro. No hay ningún número mágico, pero sí usos habituales:
| Pasos | Uso típico en tema claro |
|---|---|
| 50, 100 | Fondos muy suaves: filas alternas, avisos |
| 200, 300 | Bordes y separadores |
| 400, 500 | Iconos y elementos decorativos; texto solo si es grande |
| 600, 700 | Botones, enlaces y texto de color |
| 800, 900, 950 | Texto principal y fondos oscuros |
Lo que garantiza la legibilidad no es esa tabla sino el contraste. Es lo que tratamos a continuación.
Contraste: mídelo, no lo supongas
Las pautas de accesibilidad WCAG piden una relación de contraste de al menos 4.5:1 para texto normal y 3:1 para texto grande (unos 24 px, o 19 px en negrita). La relación compara la luminancia de dos colores, y va de 1:1 (iguales) a 21:1 (negro sobre blanco).
Estos valores se han calculado con la fórmula de WCAG a partir de los colores que pinta Chromium:
| Texto | Fondo | Contraste | ¿Texto normal? |
|---|---|---|---|
text-white | bg-indigo-600 | 6.46:1 | Sí |
text-white | bg-emerald-500 | 2.47:1 | No |
text-white | bg-amber-400 | 1.72:1 | No |
text-gray-950 | bg-amber-400 | 11.69:1 | Sí |
text-gray-600 | bg-white | 7.56:1 | Sí |
text-gray-500 | bg-white | 4.84:1 | Sí, por poco |
text-gray-400 | bg-white | 2.60:1 | No |
text-gray-400 | bg-gray-900 | 6.82:1 | Sí |
text-gray-500 | bg-gray-900 | 3.67:1 | No |
text-emerald-700 | bg-white | 5.36:1 | Sí |
text-amber-700 | bg-white | 5.03:1 | Sí |
text-red-700 | bg-white | 6.42:1 | Sí |
Saca dos conclusiones. Primera, un número no significa lo mismo en todos los colores: el blanco va bien sobre indigo-600, pero no sobre amber-400 ni sobre emerald-500. Los amarillos y verdes son muy luminosos, y en ellos conviene usar texto oscuro. Segunda, un gris que funciona en tema claro puede fallar en oscuro: por eso text-gray-500 se sustituye por text-gray-400 en dark:.
💡 Consejo: Las herramientas de desarrollo de Chrome y Firefox indican el contraste al inspeccionar un texto con el selector de color. Si usas opacidad, el contraste real depende de lo que haya detrás, y conviene medirlo en la página.
4. Qué es oklch y por qué lo usa Tailwind
La paleta pasa a oklch 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4) los colores son hexadecimales y la misma clase da otro tono:
bg-red-500es#ef4444en 3.4 y#fb2c36en 4.3. Si usas la LTS: nada que hacer, usa la paleta de 3.4 tal cual, y si compartes diseño con un proyecto v4, fija los colores clave entheme.extend.colorspara que coincidan.
Abre node_modules/tailwindcss/theme.css y verás líneas como esta:
--color-indigo-600: oklch(51.1% 0.262 276.966);
oklch() es una forma de escribir un color con tres números que corresponden a cómo lo percibimos:
Figura 3. La luminosidad, el croma y el tono de un color oklch.
| Letra | Significa | Rango | Si lo cambias… |
|---|---|---|---|
| L | Lightness, luminosidad | 0 % a 100 % | El color se aclara u oscurece |
| C | Chroma, croma | 0 a unos 0.4 | Pasa de gris a muy intenso |
| H | Hue, tono | 0 a 360 grados | Das la vuelta a la rueda de color |
Por qué no basta con hexadecimal o HSL
#4f39f6 no dice nada a simple vista. hsl() parece resolverlo, pero su “luminosidad” es una fórmula matemática y no lo que percibe el ojo. En la fila superior de la figura, todos los colores tienen la misma L en HSL y parecen de claridades muy distintas: el amarillo deslumbra y el azul casi se funde con su texto negro. En la inferior, con igual L y C en OKLCH, los seis tonos se perciben con una claridad muy parecida.

Figura 4. Arriba, seis colores con la misma luminosidad HSL. Abajo, seis colores con la misma luminosidad OKLCH.
<div class="bg-[hsl(60_100%_50%)] py-5 text-black">amarillo</div>
<div class="bg-[hsl(240_100%_50%)] py-5 text-black">azul</div>
<div class="bg-[oklch(70%_0.12_110)] py-5 text-black">amarillo</div>
<div class="bg-[oklch(70%_0.12_264)] py-5 text-black">azul</div>
Esto tiene tres ventajas prácticas:
- Paletas previsibles. Para aclarar un color basta con subir
L, sin tocar el tono. - Degradados más limpios. Se evita el gris central, como verás en la sección 9.
- Más colores.
oklchpuede expresar colores fuera de sRGB, el espacio clásico de los monitores. Una pantalla de gama amplia (P3) los muestra más saturados, y una normal los ajusta al color más próximo que pueda mostrar.
📘 Concepto: Un espacio de color es un sistema de coordenadas para describir colores. sRGB, Display P3 y Oklab son espacios distintos.
oklch()es Oklab escrito con coordenadas polares: en lugar de dos ejes rectos usa un ángulo (H) y una distancia (C).
El falso amigo: bg-red-500 no es igual en v3 y en v4
Aquí hay una trampa que la guía oficial de actualización no menciona: las clases se llaman igual, pero los valores de la paleta cambiaron. No es un error de conversión, son tonos más vivos en casi todas las familias.

Figura 5. En cada muestra, la mitad izquierda es Tailwind 3.4 y la derecha, 4.3. Debajo, los dos hexadecimales. Los grises apenas cambian.
Valores medidos: en la columna v3 está el hexadecimal de la paleta; en la v4, lo que pinta Chromium en un lienzo sRGB:
| Clase | v3.4 | v4.3 |
|---|---|---|
red-500 | #ef4444 | #fb2c36 |
red-600 | #dc2626 | #e7000b |
green-500 | #22c55e | #00c950 |
blue-600 | #2563eb | #155dfc |
indigo-600 | #4f46e5 | #4f39f6 |
amber-500 | #f59e0b | #fe9a00 |
gray-500 | #6b7280 | #6a7282 |
zinc-500 | #71717a | #71717b |
neutral-500 | #737373 | #737373 |
Las consecuencias son dos. Al migrar, un diseño cambia ligeramente de color sin que hayas tocado nada, y una captura de referencia ya no coincidirá. Y el contraste que mediste en una versión puede no valer en la otra, aunque en la mayoría de los casos la diferencia sea pequeña.
⚠️ Importante: En v3, un color
oklch()en la configuración no admite modificador de opacidad, como vimos en el módulo 02. Si tienes que copiar un color de v4 a v3, conviértelo a hexadecimal. Los de la tabla sirven para eso.
5. Opacidad con el modificador /
Tailwind permite indicar la opacidad de cualquier color con una barra:
<div class="rounded bg-indigo-600 py-6 text-center">/100</div>
<div class="rounded bg-indigo-600/75 py-6 text-center">/75</div>
<div class="rounded bg-indigo-600/50 py-6 text-center">/50</div>
<div class="rounded bg-indigo-600/25 py-6 text-center">/25</div>
<div class="rounded bg-indigo-600/5 py-6 text-center">/5</div>

Figura 6. El modificador solo afecta al fondo. opacity-50 atenúa la caja entera, incluido el texto.
/50 frente a opacity-50
Son dos cosas distintas, y conviene tenerlo claro:
<div class="rounded bg-white/50 p-3 text-gray-900">bg-white/50: el texto sigue opaco</div>
<div class="rounded bg-white p-3 text-gray-900 opacity-50">bg-white opacity-50: se atenúa todo</div>
bg-white/50 | opacity-50 | |
|---|---|---|
| Afecta a | Solo el color del fondo | El elemento y todos sus hijos |
| Propiedad CSS | background-color | opacity |
| Uso típico | Panel translúcido con texto legible | Atenuar un bloque entero, como uno deshabilitado |
opacity-* se estudia en el módulo 06.
El modificador existe en todas las familias de la sección 2: text-white/80, border-black/10, from-black/70, shadow-indigo-500/50.
⚠️ Importante: Con
text-*, la barra puede significar otra cosa.text-red-500/50aplica opacidad, porque el valor es un color.text-lg/7, en cambio, fija la altura de línea, porque el valor es un tamaño. Lo viste en Tipografía.
Qué CSS genera
El CSS que sale del compilador es:
.bg-indigo-600\/50 {
background-color: color-mix(in srgb, oklch(51.1% 0.262 276.966) 50%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-indigo-600) 50%, transparent);
}
}
Y esto es lo que llega a producción, tras pasar por Lightning CSS en vite build:
.bg-indigo-600\/50 { background-color: #4f39f680; }
@supports (color: color-mix(in lab, red, red)) {
.bg-indigo-600\/50 { background-color: color-mix(in oklab, var(--color-indigo-600) 50%, transparent); }
}
La primera declaración es una copia de seguridad: un hexadecimal con 8 cifras, donde 80 es el canal alfa. La segunda usa la variable, de modo que seguirá al tema si la redefines. La sección 15 explica color-mix().
Cualquier número y variables 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4)
/37no genera nada, porque solo admite múltiplos de 5 y no acepta variables. Si usas la LTS: escribe el valor con corchetes,bg-red-500/[.37]. Para una opacidad variable, escribe el color entero:bg-[rgb(79_70_229/var(--alfa))].
En v4 sirve cualquier número y también variables:
| Clase | Resultado |
|---|---|
bg-indigo-600/37 | Opacidad 37 % |
bg-indigo-600/[33%] | Valor arbitrario, equivalente a /33 |
bg-indigo-600/(--alfa) | Lee la variable --alfa, que debe valer un porcentaje |
<div class="h-8 bg-indigo-600/(--alfa)" style="--alfa: 30%"></div>
Medido en Chromium: oklab(0.511 0.0317755 -0.260066 / 0.3).
Adiós a bg-opacity-* 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4) funcionan
bg-opacity-*,text-opacity-*,border-opacity-*,divide-opacity-*,ring-opacity-*yplaceholder-opacity-*; v4 las elimina. Si usas la LTS: puedes seguir usándolas, aunque es mejor escribir yabg-red-500/50: funciona igual en las dos versiones.
El fallo es traicionero porque no da ningún error. bg-indigo-600 bg-opacity-50 en v4 deja un fondo totalmente opaco: bg-opacity-50 no genera CSS y el navegador no se queja. Si heredas un proyecto o copias de un tutorial antiguo, busca -opacity- en el código.
6. currentColor: el color que se hereda
currentColor es una palabra clave de CSS que significa “el valor actual de color”. Tailwind la expone con el sufijo current:
| Clase | CSS |
|---|---|
text-current | color: currentcolor |
bg-current | background-color: currentcolor |
fill-current, stroke-current | fill y stroke en SVG |
border-current | border-color: currentcolor |
Su utilidad es que todo un componente depende de una sola clase. Mira esta alerta: el icono, el borde y el fondo toman el color de text-emerald-700.
<div class="flex items-start gap-3 rounded-lg border border-current/30 bg-current/5 p-3 text-emerald-700">
<svg class="mt-0.5 size-5 shrink-0 fill-current" viewBox="0 0 20 20" aria-hidden="true">
<path d="M10 0a10 10 0 1 0 0 20 10 10 0 0 0 0-20Zm4.7 7.7-5.5 5.5a1 1 0 0 1-1.4 0l-2.5-2.5 1.4-1.4 1.8 1.8 4.8-4.8Z"/>
</svg>
<p><strong>Pedido 5001 enviado.</strong> Llegará en 48 horas.</p>
</div>
Para las otras dos variantes solo cambia text-emerald-700 por text-amber-700 o text-red-700:

Figura 7. Tres alertas que solo se diferencian en una clase.
📘 Concepto:
fill-currentes la forma estándar de colorear un icono SVG inline. Así, un icono dentro de un enlace cambia de color con él enhover:sin tocar el SVG. Las imágenes cargadas con<img>no heredancolor, y por eso esto solo funciona con SVG integrado en el HTML.
Recuerda también que el valor por defecto de los bordes en v4 es currentColor: lo explica el módulo 06.
Opacidad sobre currentColor 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4)
bg-current/5yborder-current/30no generan nada, porque v3 no sabe aplicar opacidad a una palabra clave. Si usas la LTS: escribe el fondo con un valor arbitrario,bg-[color-mix(in_srgb,currentColor_5%,transparent)], que funciona en navegadores concolor-mix(), o repite el color:bg-emerald-700/5.
Por dentro, v4 emite color-mix(in oklab, currentcolor 5%, transparent). La copia de seguridad para navegadores sin color-mix() es background-color: currentColor, un fondo opaco igual que el texto, pero eso solo afecta a navegadores por debajo del mínimo de v4.
7. Colores de fondo con valores propios
Cuando el color no está en la paleta, tienes tres caminos, y cada uno tiene su sitio.
| Situación | Solución | Ejemplo |
|---|---|---|
| Color de marca que se repite | Añadirlo al tema | --color-marca y bg-marca |
| Un caso aislado | Valor arbitrario | bg-[#0a7] |
| Color que llega en tiempo de ejecución | Variable CSS | bg-(--marca) |
Variables en valores arbitrarios 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4) no existe la sintaxis con paréntesis. Si usas la LTS: escribe
bg-[var(--marca)], y para imágenesbg-[image:var(--fondo)]. Esas dos formas funcionan también en v4.
<div class="h-8 bg-(--marca)" style="--marca: #0a7"></div>
<div class="h-8 bg-(--marca)/50" style="--marca: #0a7"></div>
<div class="h-8 bg-(image:--fondo)" style="--fondo: linear-gradient(red, blue)"></div>
Hay un detalle importante. Con una variable, Tailwind no puede saber qué contiene, así que da por hecho que es un color. Si la variable guarda un degradado, hay que indicar el tipo:
| Clase | --fondo: linear-gradient(red, blue) | Motivo |
|---|---|---|
bg-(--fondo) | No pinta nada | Genera background-color, y un degradado no es un color |
bg-(image:--fondo) | Funciona | Genera background-image |
Medido en Chromium: la primera se queda con background-image: none y fondo transparente, sin ningún error en la consola.
8. Gradientes lineales 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4) la clase es
bg-gradient-to-re interpola en sRGB; v4 la renombra abg-linear-to-re interpola en Oklab. Si usas la LTS: escribebg-gradient-to-r,bg-gradient-to-tl… y deja igualfrom-*,via-*yto-*, que se escriben igual.
Un degradado se describe con dos ingredientes: dirección y colores.
<div class="h-16 rounded bg-linear-to-r from-indigo-600 to-cyan-300"></div>
En 4.3.3, bg-gradient-to-r sigue generando CSS como alias obsoleto, pero ya con in oklab. Es decir, un proyecto migrado no se rompe, aunque sus degradados cambien de aspecto.
Direcciones
Hay ocho, con la misma nomenclatura que el resto de Tailwind: t (top), r (right), b (bottom), l (left).

Figura 8. Las ocho direcciones y dos ángulos. El nombre indica hacia dónde va el color final.
La dirección indica hacia dónde va el degradado: bg-linear-to-t empieza abajo y llega arriba.
Ángulos 🆕 v4.0
🆕 Desde Tailwind 4.0. No existe en la LTS (Tailwind 3.4). Si usas la LTS: escribe el ángulo en un valor arbitrario y usa las paradas de Tailwind:
bg-[linear-gradient(65deg,var(--tw-gradient-stops))].
bg-linear-65 admite cualquier número de grados, y con un guion delante, -bg-linear-45, el ángulo es negativo:
.-bg-linear-45 {
--tw-gradient-position: calc(45deg * -1) in oklab;
background-image: linear-gradient(var(--tw-gradient-stops));
}
Como en CSS, 0 grados apunta hacia arriba y el ángulo crece en el sentido de las agujas del reloj: bg-linear-90 equivale a bg-linear-to-r.
Paradas: from, via, to
<div class="h-9 rounded bg-linear-to-r from-rose-500 to-amber-400"></div>
<div class="h-9 rounded bg-linear-to-r from-rose-500 via-fuchsia-500 to-indigo-500"></div>
<div class="h-9 rounded bg-linear-to-r from-rose-500 from-20% via-fuchsia-500 via-30% to-indigo-500 to-90%"></div>
<div class="h-9 rounded bg-linear-to-r from-indigo-600 from-50% to-amber-400 to-50%"></div>
<div class="h-9 rounded bg-linear-to-r from-rose-500"></div>
<div class="h-9 rounded bg-linear-to-r to-rose-500"></div>

Figura 9. Paradas de color y posiciones.
| Clase | Qué define | Por defecto |
|---|---|---|
from-rose-500 | Color inicial | Transparente |
via-fuchsia-500 | Color intermedio | Ninguno |
to-indigo-500 | Color final | Transparente |
from-20% | Dónde empieza el color inicial | 0% |
via-30% | Dónde está el intermedio | 50% |
to-90% | Dónde acaba el color final | 100% |
Observa tres cosas en la figura:
- Las posiciones no sustituyen al color: son clases aparte,
from-rose-500 from-20%. - Si dos paradas coinciden en el mismo punto (
from-50%yto-50%), no hay transición y obtienes un corte brusco: dos colores sólidos en la misma caja. - Si falta una parada, se usa transparente. Es lo que permite “fundir” un color con lo que hay debajo.
Esta última propiedad es la base de los velos sobre imágenes: from-black/70 to-transparent.
Qué ocurre por dentro
Un degradado de CSS es una sola declaración, pero Tailwind la divide en varias clases. ¿Cómo lo consigue? Con variables CSS: cada clase rellena la suya, y al final se combinan.
Figura 10. Cada clase aporta una variable, y background-image las une.
.bg-linear-to-r {
--tw-gradient-position: to right in oklab;
background-image: linear-gradient(var(--tw-gradient-stops));
}
.from-rose-500 {
--tw-gradient-from: var(--color-rose-500);
--tw-gradient-stops: var(--tw-gradient-via-stops,
var(--tw-gradient-position),
var(--tw-gradient-from) var(--tw-gradient-from-position),
var(--tw-gradient-to) var(--tw-gradient-to-position));
}
Las variables se declaran con @property con valor inicial #0000, un transparente. Esto explica que las paradas omitidas sean transparentes y que el orden de las clases dé igual.
Variantes en gradientes 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4) cambiar
from-*en una variante reinicia el color final a transparente; en v4 se conserva. Si usas la LTS: repite todas las paradas en la variante:dark:from-blue-500 dark:to-yellow-400. Tampoco existevia-none: en v3 el propio reinicio ya elimina elvia.
Como cada clase toca una sola variable, en v4 puedes cambiar solo una parada:
<div class="bg-linear-to-r from-red-500 to-yellow-400 dark:from-blue-500"></div>
En tema oscuro, medido en Chromium:
Tailwind 4.3.3 linear-gradient(to right, oklch(0.623 0.214 259.815) 0%, oklch(0.852 0.199 91.936) 100%)
Tailwind 3.4.19 linear-gradient(to right, rgb(59, 130, 246), rgba(59, 130, 246, 0))
En v4 el final sigue siendo amarillo. En v3 pasa a ser azul transparente, porque from-* escribe a la vez --tw-gradient-to, y por tanto la variante pisa el to-yellow-400.
La otra cara es que, en v4, un via-* también se conserva. Si en una variante quieres volver a dos paradas, tienes que quitarlo:
<div class="bg-linear-to-r from-red-500 via-orange-400 to-yellow-400
dark:via-none dark:from-blue-500 dark:to-teal-400"></div>
Valores arbitrarios
Si necesitas varias paradas o más de tres colores, escribe el degradado completo. Los espacios se sustituyen por _:
<div class="h-16 bg-linear-[25deg,red_5%,yellow_60%,lime_90%,teal]"></div>
<div class="h-16 bg-linear-(--mi-degradado)"></div>
Las paradas también admiten valores arbitrarios: from-[#0a7], via-(--marca), to-[oklch(70%_0.12_264)].
9. Interpolación: el camino entre dos colores 🆕 v4.0
🆕 Desde Tailwind 4.0. No existe en la LTS (Tailwind 3.4), que siempre interpola en sRGB. Si usas la LTS: escribe el degradado arbitrario con el espacio de color,
bg-[linear-gradient(to_right_in_oklab,theme(colors.blue.600),theme(colors.yellow.300))]. Solo funciona en navegadores modernos, de modo que conviene añadir unbg-blue-600debajo.
Un degradado de azul a amarillo tiene que decidir qué colores pasan por el medio. Pensemos en coordenadas: si dibujas una línea recta entre dos puntos, el resultado depende del mapa. Cada espacio de color es un mapa diferente.
<div class="h-8 rounded bg-linear-to-r/srgb from-blue-600 to-yellow-300"></div>
<div class="h-8 rounded bg-linear-to-r from-blue-600 to-yellow-300"></div>
<div class="h-8 rounded bg-linear-to-r/oklch from-blue-600 to-yellow-300"></div>
<div class="h-8 rounded bg-linear-to-r/hsl from-blue-600 to-yellow-300"></div>
<div class="h-8 rounded bg-linear-to-r/longer from-blue-600 to-yellow-300"></div>

Figura 11. El mismo degradado con siete modificadores. Solo cambia el camino.
| Modificador | CSS generado | Camino |
|---|---|---|
/srgb | in srgb | Línea recta en RGB. Con colores opuestos, el centro sale gris |
/oklab (por defecto) | in oklab | Recta en Oklab. Centro más claro y regular |
/lab, /lch | in lab, in lch | Variantes del espacio CIE |
/hsl | in hsl | Rodea la rueda de color: muy vivo |
/oklch | in oklch | Rodea la rueda por el camino corto |
/shorter | in oklch shorter hue | Igual que /oklch |
/longer | in oklch longer hue | Rodea la rueda por el camino largo |
/increasing | in oklch increasing hue | Siempre con el tono creciente |
/decreasing | in oklch decreasing hue | Siempre con el tono decreciente |
Por qué sale gris
Un azul y un amarillo son casi opuestos. Al promediar sus coordenadas en un espacio rectangular se obtiene algo cercano al centro, y el centro es gris. Los espacios polares, como oklch, no cruzan por el centro sino que rodean la rueda manteniendo el croma: el resultado pasa por tonos intermedios (aquí, verdes). Es más vivo, pero introduce colores que no están ni en el inicio ni en el final.
Cómo se reparten longer, increasing y decreasing
El tono es un ángulo, y de un ángulo a otro siempre hay dos caminos. blue-600 tiene un tono cercano a 264 grados y yellow-300, cercano a 100:
- El camino corto baja de 264 a 100, pasando por los verdes. Por eso, en la figura,
/decreasingcoincide con/oklch. - El camino largo sube de 264 a 360 y sigue hasta 100, pasando por morados, rosas y naranjas. Por eso
/increasingcoincide con/longer.
Con otra pareja de colores, las coincidencias serían otras.
¿Cuál elijo?
- Deja el valor por defecto (
oklab) casi siempre. Funciona bien y no introduce tonos ajenos. - Usa
/oklchpara degradados vivos entre colores alejados, y mira el resultado: en la figura se aprecia una transición brusca cerca del verde, debida a que algunos valores intermedios caen fuera de lo que puede mostrar sRGB. - Usa
/srgbsi tienes que clavar el aspecto de un diseño de v3. - Con dos tonos cercanos, las diferencias son pequeñas y no merece la pena preocuparse.
Otra forma de dirigir el camino es añadir una parada: via-emerald-400 hace que un degradado de oklab pase por el verde sin cambiar de espacio.
💡 Consejo: El modificador se aplica también a radiales y cónicos:
bg-radial/oklch,bg-conic/longer.
El mismo degradado en la LTS
Estos son resultados reales de un proyecto compilado con Tailwind 3.4.19:

Figura 12. Equivalentes en Tailwind 3.4. El segundo y el tercer degradado son valores arbitrarios que ya no dependen del compilador sino del navegador.
La fila de cuadrados adelanta otros equivalentes para 3.4 que verás en las cajas de este módulo. De izquierda a derecha: radial, cónico, bg-[length:...], bg-[position:...], un color propio con opacidad y color-mix().
10. Gradientes radiales y cónicos 🆕 v4.0
🆕 Desde Tailwind 4.0. No existen en la LTS (Tailwind 3.4). Si usas la LTS: las paradas
from-*yto-*funcionan dentro de un valor arbitrario:bg-[radial-gradient(var(--tw-gradient-stops))]ybg-[conic-gradient(from_180deg,var(--tw-gradient-stops))].
<div class="size-36 bg-radial from-amber-300 to-rose-600"></div>
<div class="size-36 bg-radial from-amber-300 from-30% to-rose-600 to-70%"></div>
<div class="size-36 bg-radial-[at_25%_25%] from-white to-indigo-700"></div>
<div class="size-36 bg-radial-[circle_closest-side] from-amber-300 from-90% to-transparent to-90%"></div>
<div class="size-36 rounded-full bg-conic from-indigo-600 to-cyan-300"></div>
<div class="size-36 rounded-full bg-conic-180 from-indigo-600 to-cyan-300"></div>
<div class="size-36 rounded-full bg-conic/longer from-red-500 to-red-500"></div>
<div class="size-36 rounded-full bg-conic-[from_90deg] from-indigo-600 to-cyan-300"></div>

Figura 13. Arriba, degradados radiales. Abajo, cónicos, entre ellos una rueda de color completa.
Radial. bg-radial parte del centro hacia fuera. Entre corchetes va lo que iría antes de los colores en radial-gradient(): la forma, el tamaño y la posición.
Cónico. bg-conic gira alrededor del centro, empezando arriba. El número de bg-conic-180 es el ángulo inicial, y no hace falta nada más para situar el corte donde quieras.
La rueda de color es un buen ejemplo de la sección anterior: from-red-500 to-red-500 tiene el mismo color al principio y al final. En sRGB sería un círculo rojo, pero con /longer el tono da la vuelta completa y pasa por todos los colores.
⚠️ Importante: Con posición arbitraria, la clase no añade
in oklab:bg-radial-[at_25%_25%]genera--tw-gradient-position: at 25% 25%. Si quieres fijar el espacio, escríbelo también:bg-radial-[at_25%_25%_in_oklab]. Chromium acepta la sintaxis.
Gráficos con degradados cónicos
Un degradado cónico con cortes bruscos es un gráfico circular sin JavaScript:
<div class="grid size-40 place-items-center rounded-full
bg-[conic-gradient(var(--color-indigo-600)_0_45%,var(--color-amber-400)_0_75%,var(--color-gray-200)_0)]">
<div class="grid size-28 place-items-center rounded-full bg-white text-sm font-bold">Ventas</div>
</div>
El truco es que cada color indica dónde acaba, y la parada 0 significa “justo donde terminó el anterior”. El ejercicio 5 lo desarrolla.
📘 Concepto:
bg-conic-[...]ybg-radial-[...]tienen dos usos. Si hay clasesfrom-*oto-*, el valor es lo que va antes de los colores, comofrom_90deg. Si no las hay, el valor se usa como lista completa, porque generaconic-gradient(var(--tw-gradient-stops, valor)):bg-conic-[var(--color-indigo-600)_0_45%,var(--color-amber-400)_0_75%,var(--color-gray-200)_0]da el mismo gráfico. Aquí usobg-[conic-gradient(...)]porque se escribe igual en 3.4.
11. Imágenes de fondo
Una imagen se indica con un valor arbitrario:
<div class="h-28 bg-gray-200 bg-[url(/img/escena.svg)] bg-cover bg-center"></div>
La clase bg-gray-200 no sobra: si la imagen tarda en cargar o falla, se ve ese color y el texto encima sigue siendo legible.
En v4 y en 3.4 funciona sin comillas. En 3.4 también puedes escribir bg-[url('/img/escena.svg')].

Figura 14. Tamaño, repetición y posición de una imagen de fondo.
Tamaño
| Clase | CSS | Efecto |
|---|---|---|
bg-auto | background-size: auto | Tamaño natural |
bg-cover | background-size: cover | Cubre la caja y recorta lo que sobra |
bg-contain | background-size: contain | Se ve entera y puede dejar huecos |
Repetición
| Clase | CSS | Efecto |
|---|---|---|
bg-repeat | background-repeat: repeat | Mosaico, por defecto |
bg-no-repeat | no-repeat | Una sola vez |
bg-repeat-x, bg-repeat-y | repeat-x, repeat-y | En un solo eje |
bg-repeat-round | round | Deforma un poco para que quepan piezas enteras |
bg-repeat-space | space | Reparte piezas enteras dejando huecos |
Compara bg-repeat, que corta las piezas en el borde, con bg-repeat-round, que las estira, y bg-repeat-space, que las separa.
Posición
bg-center, bg-top, bg-bottom, bg-left y bg-right funcionan igual en las dos versiones. Importan sobre todo con bg-cover, porque deciden qué parte se recorta: en una imagen vertical dentro de una caja apaisada, bg-top conserva la parte superior y bg-center recorta por arriba y por abajo.
Esquinas: bg-top-left 🆕 v4.1
🆕 Desde Tailwind 4.1. No existe en la LTS (Tailwind 3.4). Si usas la LTS: usa el orden antiguo:
bg-left-top,bg-right-top,bg-left-bottomybg-right-bottom. Esas clases también funcionan en 4.3.3.
| v4.1 y posteriores | Orden antiguo | CSS |
|---|---|---|
bg-top-left | bg-left-top | background-position: left top |
bg-top-right | bg-right-top | right top |
bg-bottom-left | bg-left-bottom | left bottom |
bg-bottom-right | bg-right-bottom | right bottom |
Valores propios: bg-size-* y bg-position-* 🆕 v4.1
🆕 Desde Tailwind 4.1. No existe en la LTS (Tailwind 3.4) ni en 4.0. Si usas la LTS: indica el tipo dentro de los corchetes:
bg-[length:20px_20px]ybg-[position:10px_10px]. Estas clases siguen funcionando en v4.
<div class="h-28 bg-gray-200 bg-[url(/img/motivo.svg)] bg-size-[20px_20px]"></div>
<div class="h-28 bg-gray-200 bg-[url(/img/escena.svg)] bg-size-[50%] bg-position-[right_1rem_bottom_1rem] bg-no-repeat"></div>
Tailwind tiene que distinguir estas clases porque todas empiezan por bg-: un valor entre corchetes podría ser un color, una imagen, un tamaño o una posición. Con bg-size- no hay duda. Con la forma bg-[length:...] era el prefijo de tipo el que deshacía la ambigüedad.
Fijación al desplazar
| Clase | CSS | Efecto al desplazar la página |
|---|---|---|
bg-scroll | background-attachment: scroll | El fondo se mueve con la caja |
bg-fixed | fixed | El fondo queda fijo respecto a la ventana |
bg-local | local | El fondo se desplaza con el contenido de la propia caja |
bg-fixed da el efecto de “ventana” en cabeceras, pero conviene probarlo en móviles, donde el comportamiento varía y el coste de pintar es mayor.
¿bg-* o <img>?
Es una decisión de contenido, no de estilo:
- Usa
<img>conobject-coversi la imagen es contenido, como la foto de un producto. Llevaalt, la lee un lector de pantalla, y el navegador puede cargarla en diferido.object-*se ve en el módulo 07. - Usa
bg-[url(...)]si la imagen es decoración: texturas, cabeceras, motivos.
12. Varias capas de fondo
Tanto una imagen como un degradado son background-image. Y aquí está uno de los errores más frecuentes.
<!-- Mal: dos clases sobre la misma propiedad -->
<div class="h-36 bg-linear-to-t from-black/70 to-transparent bg-[url(/img/escena.svg)] bg-cover"></div>
Las dos clases escriben en background-image, y solo gana una. Medido en Chromium: la propiedad vale url("/img/escena.svg") y el degradado desaparece.
Hay dos soluciones correctas:
<!-- Bien: el degradado va en una capa hija -->
<div class="relative h-36 overflow-hidden rounded-lg bg-[url(/img/escena.svg)] bg-cover">
<div class="absolute inset-0 bg-linear-to-t from-black/70 to-transparent"></div>
<p class="absolute bottom-2 left-3 font-semibold text-white">Portátil Gaming 16</p>
</div>
<!-- Bien: dos capas en un solo valor arbitrario -->
<div class="flex h-36 items-end rounded-lg bg-[linear-gradient(to_top,rgb(0_0_0/0.7),transparent),url(/img/escena.svg)] bg-cover p-3 font-semibold text-white">
Portátil Gaming 16
</div>

Figura 15. Sin degradado, con una capa hija y con dos capas en un mismo valor.
| Solución | Ventajas | Inconvenientes |
|---|---|---|
| Capa hija | Clases normales, admite hover: y paleta | Añade un div, requiere relative |
| Valor arbitrario | Sin HTML extra | Clase larga, sin variantes sencillas |
En un valor con varias capas, la primera queda encima, y por eso el degradado va antes que la imagen. Sin el velo, el texto blanco sería ilegible sobre las zonas claras de la imagen: el degradado no es decoración, es lo que garantiza el contraste.
13. bg-clip-* y bg-origin-*
Por defecto, el fondo se pinta en toda la caja, incluso debajo del borde. bg-clip-* limita dónde se ve, y bg-origin-* decide desde dónde se mide la imagen.

Figura 16. Texto con degradado, bg-clip-*, bg-origin-* y borde en degradado.
| Clase | background-clip | El fondo llega hasta |
|---|---|---|
bg-clip-border | border-box | Debajo del borde (por defecto) |
bg-clip-padding | padding-box | El borde interior |
bg-clip-content | content-box | El contenido |
bg-clip-text | text | La forma de las letras |
| Clase | background-origin | La imagen se coloca respecto a |
|---|---|---|
bg-origin-border | border-box | El exterior del borde |
bg-origin-padding | padding-box | El interior del borde (por defecto) |
bg-origin-content | content-box | El contenido |
bg-clip-padding y su uso con bordes translúcidos se tratan en el módulo 06.
Texto con degradado
Se necesitan cuatro cosas: un degradado, bg-clip-text, text-transparent y, casi siempre, w-fit.
<h2 class="w-fit bg-linear-to-r from-indigo-600 via-fuchsia-500 to-rose-500
bg-clip-text text-5xl font-extrabold text-transparent">
Rebajas de otoño
</h2>
Cada clase tiene su papel:
bg-clip-textrecorta el fondo con la forma de las letras.text-transparentdeja ver ese fondo. Sin ella, el texto normal lo tapa y no se aprecia nada.w-fitajusta el ancho al texto. Un encabezado es un bloque que ocupa toda la línea, y el degradado se reparte en ese ancho: sinw-fit, un título corto se queda en el primer tramo y nunca alcanza el color final.
Tailwind solo escribe background-clip: text, pero al compilar para producción Lightning CSS añade -webkit-background-clip: text, que siguen necesitando algunos navegadores:
.bg-clip-text{-webkit-background-clip:text;background-clip:text}
⚠️ Importante: El contraste de un texto transparente no lo mide bien ninguna herramienta automática, y tienes que comprobar a mano cada zona del degradado. Reserva este efecto para títulos grandes, nunca para texto de lectura.
Borde en degradado
border-* no admite degradados de forma directa, pero se resuelve con dos cajas: la exterior lleva el degradado y un relleno de 2 px, y la interior tapa el centro.
<div class="w-72 rounded-xl bg-linear-to-r from-indigo-600 to-rose-500 p-0.5">
<div class="rounded-[10px] bg-white p-3 text-sm font-semibold text-gray-900">
Borde en degradado con dos cajas
</div>
</div>
El radio interior es 10 px porque rounded-xl vale 12 px y el relleno, 2 px. Con radios iguales se ve un hueco en las esquinas.
14. Las paletas nuevas 🆕 v4.2
🆕 Desde Tailwind 4.2. No existen en la LTS (Tailwind 3.4) ni en 4.0 y 4.1. Si usas la LTS: copia los hexadecimales de la tabla de esta sección en
theme.extend.colorsdel ficherotailwind.config.js. Admiten modificador de opacidad.
taupe, mauve, mist y olive son grises con un matiz perceptible. Los grises clásicos también lo tienen (slate tira a azul), pero muy discreto; estos cuatro dan a una interfaz más carácter sin llegar a parecer de color.

Figura 17. Comparación de stone y slate con las cuatro paletas nuevas. Las diferencias se aprecian sobre todo en los pasos 400 a 700.
| Paleta | Matiz | Combina con |
|---|---|---|
taupe | Marrón grisáceo, cálido | Naranjas, ámbar |
mauve | Malva, tira a morado | Violetas, rosas |
mist | Azul verdoso, frío | Cian, azules |
olive | Verde oliva | Verdes, lima |
<article class="rounded-xl border border-mauve-200 bg-mauve-50 p-5">
<h3 class="font-bold text-mauve-900">Portátil UltraBook 14</h3>
<p class="text-sm text-mauve-600">Portátil ligero de 14 pulgadas, 16 GB RAM</p>
</article>
Los hexadecimales de esta tabla son los que pinta Chromium en sRGB:
| Paso | taupe | mauve | mist | olive |
|---|---|---|---|---|
| 50 | #fbfaf9 | #fafafa | #f9fbfb | #fbfbf9 |
| 100 | #f3f1f1 | #f3f1f3 | #f1f3f3 | #f4f4f0 |
| 200 | #e8e4e3 | #e7e4e7 | #e3e7e8 | #e8e8e3 |
| 300 | #d8d2d0 | #d7d0d7 | #d0d6d8 | #d8d8d0 |
| 400 | #aba09c | #a89ea9 | #9ca8ab | #abab9c |
| 500 | #7c6d67 | #79697b | #67787c | #7c7c67 |
| 600 | #5b4f4b | #594c5b | #4b585b | #5b5b4b |
| 700 | #473c39 | #463947 | #394447 | #474739 |
| 800 | #2b2422 | #2a212c | #22292b | #2b2b22 |
| 900 | #1d1816 | #1d161e | #161b1d | #1d1d16 |
| 950 | #0c0a09 | #0c090c | #090b0c | #0c0c09 |
En v3 quedaría así (comprobado: bg-mauve-500/50 genera rgb(121 105 123 / 0.5)):
// tailwind.config.js
export default {
content: ['./*.html'],
theme: {
extend: {
colors: {
mauve: { 50: '#fafafa', 100: '#f3f1f3', 500: '#79697b', 900: '#1d161e' /* ... */ },
},
},
},
};
15. color-mix(): mezclar colores 🔄 v4.0
🔄 Cambia en Tailwind 4.0. En la LTS (Tailwind 3.4) el compilador no usa
color-mix(): la opacidad se calcula al compilar y dargb(239 68 68 / 0.5). Si usas la LTS: los modificadores de opacidad funcionan sin él. Para mezclar colores, escribe el valor arbitrario,bg-[color-mix(in_oklab,theme(colors.indigo.600)_25%,white)], en navegadores que lo admitan.
color-mix() es una función de CSS que combina dos colores en la proporción que le indiques, dentro de un espacio de color:
color-mix(in oklab, var(--color-indigo-600) 25%, white)
Se lee así: “en Oklab, mezcla un 25 % de índigo con el resto de blanco”. Si omites el porcentaje, es 50 %.
Este es el motivo de que el modificador de opacidad funcione con cualquier color: mezclar con transparent es bajar la opacidad. En v3 había que descomponer el color en canales al compilar, y por eso no admitía oklch(), variables ni currentColor. En v4 la operación la hace el navegador, y a color-mix() le da igual el formato.
<div class="h-14 rounded bg-[color-mix(in_oklab,var(--color-indigo-600)_75%,white)]"></div>
<div class="h-14 rounded bg-[color-mix(in_oklab,var(--color-indigo-600)_50%,white)]"></div>
<div class="h-14 rounded bg-[color-mix(in_oklab,var(--color-indigo-600)_25%,white)]"></div>
<div class="h-14 rounded bg-[color-mix(in_oklab,var(--color-indigo-600)_10%,white)]"></div>

Figura 18. Arriba, índigo con distintas proporciones de blanco. Debajo, la misma mezcla de azul y amarillo en dos espacios. Abajo, una caja que usa --alpha().
El espacio de color importa igual que en los degradados: la mezcla de azul y amarillo da un gris verdoso en srgb y un azul grisáceo más claro en oklab.
Derivar colores en el tema
El uso más potente está en @theme: defines la marca una vez y derivas los demás tonos. Así cambias un valor y todo lo demás lo sigue.
@import "tailwindcss";
@theme {
--color-marca: oklch(52% 0.17 200);
--color-marca-suave: color-mix(in oklab, var(--color-marca) 12%, white);
--color-marca-oscura: color-mix(in oklab, var(--color-marca) 70%, black);
}
<div class="flex items-center gap-2 rounded-lg bg-marca-suave p-3">
<span class="rounded bg-marca px-3 py-1 text-sm font-semibold text-white">Marca</span>
<span class="rounded border border-marca/40 bg-marca/10 px-3 py-1 text-sm font-semibold text-marca-oscura">Marca suave</span>
</div>
Al compilar para producción, Lightning CSS calcula la mezcla en una declaración de seguridad y deja la original detrás de @supports:
:root, :host { --color-marca-suave: #e0eff0; }
@supports (color: color-mix(in lab, red, red)) {
:root, :host { --color-marca-suave: color-mix(in oklab, var(--color-marca) 12%, white); }
}
📘 Concepto: Esa copia de seguridad se calcula al compilar. Por eso no es posible cuando el valor se conoce solo al ejecutar: con
bg-indigo-600/(--alfa), sincolor-mix()el fondo se queda opaco, y lo mismo pasa conbg-current/5.
La función --alpha() 🆕 v4.0
🆕 Desde Tailwind 4.0. No existe en la LTS (Tailwind 3.4). Si usas la LTS: usa
theme()en tu CSS con la opacidad,theme(colors.lime.300 / 50%), o el valor hexadecimal con alfa.
En tu propio CSS no hay modificadores, pero Tailwind ofrece esta función, equivalente a /50:
.caja-alfa {
background-color: --alpha(var(--color-lime-300) / 50%);
}
En producción se convierte en #bbf45180 más una regla @supports con color-mix(). Es decir, lo mismo que hace una clase con modificador.
16. accent-*, caret-* y otros colores de formulario
Los controles de formulario tienen colores propios, y CSS ofrece propiedades específicas para ellos.
<form class="space-y-3 text-sm accent-indigo-600">
<label class="flex items-center gap-2"><input type="checkbox" checked> Recibir ofertas</label>
<label class="flex items-center gap-2"><input type="radio" name="e" checked> Envío urgente</label>
<label class="flex items-center gap-2 accent-rose-500"><input type="checkbox" checked> Con su propio color</label>
<label class="flex items-center gap-3">Cantidad <input type="range" value="60" class="w-48"></label>
<input type="text" value="Portátil"
class="w-full rounded border border-gray-300 px-3 py-2 caret-rose-500 selection:bg-amber-300 selection:text-gray-900">
<input type="text" placeholder="Busca por nombre de producto"
class="w-full rounded border border-gray-300 px-3 py-2 placeholder:text-indigo-400">
</form>

Figura 19. accent-indigo-600 en el formulario y accent-rose-500 en una etiqueta. El cursor del primer campo es rosa, con caret-rose-500. La barra verde es el problema que se explica más abajo.
| Clase | Propiedad | Afecta a |
|---|---|---|
accent-indigo-600 | accent-color | Casillas, radios, range |
accent-auto | accent-color: auto | Vuelve al color del navegador |
caret-rose-500 | caret-color | Cursor de escritura |
selection:bg-amber-300 | background-color en ::selection | Texto seleccionado |
placeholder:text-indigo-400 | color en ::placeholder | Texto de ayuda |
accent-color se hereda, de modo que basta con ponerlo en el <form>, y un hijo puede cambiarlo. Es la forma más económica de dar marca a un formulario: una sola clase, y el navegador sigue encargándose del foco y de la accesibilidad. El navegador incluso elige el color de la marca de verificación según el contraste con tu color.
selection: es una variante aplicada al pseudoelemento ::selection, también heredable:

Figura 20. La misma entrada con el texto seleccionado.
accent-* no pinta <progress> con Preflight
Mira la figura 19: la barra de progreso sale verde y gris, y no índigo. En teoría, accent-color afecta a <progress>. Al investigarlo en Chromium, esto es lo que ocurre:
| Prueba | Resultado |
|---|---|
<progress> sin Tailwind, con accent-color | Barra redondeada del color indicado |
Igual, con border: 0 solid | Barra plana verde: ignora accent-color |
Igual, con border: none | Barra plana verde: ignora accent-color |
Preflight pone border: 0 solid a todos los elementos, como viste en el módulo 02. Esa regla basta para que Chromium abandone el dibujo nativo del control, y accent-color deja de tener efecto. Se resuelve estilizando sus pseudoelementos:
<progress value="70" max="100"
class="h-2 w-64 overflow-hidden rounded-full bg-gray-200
[&::-moz-progress-bar]:bg-indigo-600
[&::-webkit-progress-bar]:bg-gray-200
[&::-webkit-progress-value]:bg-indigo-600"></progress>

Figura 21. Arriba, accent-indigo-600 con Preflight activo. Abajo, la versión con pseudoelementos.
Chromium y Firefox usan nombres de pseudoelemento distintos, y por eso aparecen los tres. La variante [&...] es un selector arbitrario, que se estudia en el módulo 11. Los formularios completos, con el plugin @tailwindcss/forms, están en el módulo 17.
Controles en tema oscuro: scheme-* 🆕 v4.0
🆕 Desde Tailwind 4.0. No existe en la LTS (Tailwind 3.4). Si usas la LTS: usa una propiedad arbitraria:
[color-scheme:dark].
color-scheme indica al navegador si la página es clara u oscura, y con eso adapta las barras de desplazamiento y los controles nativos: scheme-dark, scheme-light, scheme-light-dark. Lo aplicarás en el módulo 12.
17. Caso real: portada de la tienda EMPRESA
Juntamos lo aprendido: imagen de fondo, velo, texto con degradado, botón con degradado y etiquetas de estado.
<div class="space-y-4 bg-gray-50 p-5 dark:bg-gray-950">
<section class="relative overflow-hidden rounded-2xl bg-[url(/img/escena.svg)] bg-cover bg-center">
<div class="absolute inset-0 bg-linear-to-r from-indigo-950/90 via-indigo-950/60 to-transparent"></div>
<div class="relative max-w-md p-8 text-white">
<p class="text-xs font-semibold tracking-wider text-amber-300 uppercase">Hasta el 30 de noviembre</p>
<h2 class="mt-1 w-fit bg-linear-to-r from-white to-amber-200 bg-clip-text text-3xl font-extrabold text-transparent">
Rebajas en portátiles
</h2>
<p class="mt-2 text-sm text-white/80">Renueva tu equipo con los mejores precios de EMPRESA.</p>
<a href="#" class="mt-4 inline-block rounded-lg bg-linear-to-r from-amber-400 to-orange-500 px-4 py-2
text-sm font-semibold text-gray-950 hover:from-amber-300 hover:to-orange-400">
Ver ofertas
</a>
</div>
</section>
<div class="grid grid-cols-3 gap-4">
<article class="rounded-xl border border-gray-200 bg-white p-5 dark:border-white/10 dark:bg-gray-900">
<span class="rounded-full bg-emerald-500/10 px-2 py-0.5 text-xs font-semibold text-emerald-700 dark:text-emerald-400">
En stock
</span>
<h3 class="mt-3 font-bold text-gray-900 dark:text-white">Portátil UltraBook 14</h3>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">Portátil ligero de 14 pulgadas, 16 GB RAM</p>
<p class="mt-3 text-2xl font-bold text-gray-900 dark:text-white">899 €</p>
</article>
<!-- Las otras dos tarjetas: Torre Workstation con amber y Portátil Gaming 16 con indigo -->
</div>
</div>

Figura 22. La portada en tema claro.

Figura 23. La misma portada con prefers-color-scheme: dark.
Vale la pena fijarse en varias decisiones:
- El velo decide la legibilidad.
from-indigo-950/90se oscurece a la izquierda, donde va el texto, yto-transparentdeja ver la imagen a la derecha.relativeen el contenido lo sitúa por encima de la capaabsolute. - El botón usa texto oscuro. Ya vimos que
text-whitesobre ámbar da 1.72:1, ytext-gray-950da 11.69:1. hover:cambia solo dos variables. El degradado no se reescribe: basta con cambiarfromyto.- La etiqueta funciona en los dos temas.
bg-emerald-500/10es translúcido y se adapta a lo que tiene detrás, de modo que solo cambia el color del texto. dark:border-white/10es un borde que no depende de un gris concreto. Un blanco translúcido se ve bien sobre cualquier fondo oscuro.
La variante dark: se explica en el módulo 12. hover:from-* y dark: no necesitan repetir las otras paradas en v4; en v3 sí, como explica la sección 8.
18. Errores frecuentes
| Síntoma | Causa | Solución |
|---|---|---|
| El fondo sale opaco tras migrar | bg-opacity-50 ya no existe en v4 | bg-red-500/50 |
| El degradado no se ve | Falta from-* o to-*, o la caja no tiene altura | Revisa dirección, paradas y tamaño |
bg-linear-to-r no hace nada | Estás en 3.4 | bg-gradient-to-r |
| La imagen tapa el degradado | Dos clases sobre background-image | Capa hija o valor arbitrario con dos capas |
| El texto con degradado no se ve | Falta text-transparent o bg-clip-text | Añade las dos |
| El degradado de un título no llega al último color | El bloque es más ancho que el texto | w-fit o inline-block |
| El centro del degradado sale gris | Colores opuestos en sRGB | Quita /srgb, usa /oklch o añade via-* |
| El color “ha cambiado” al migrar | Paleta distinta en v4 | Fija el color en el tema |
bg-(--fondo) no muestra un degradado | La variable se trata como color | bg-(image:--fondo) |
bg-${color}-500 no pinta | Clase dinámica que el escáner no ve | Clase completa en el código (módulo 02) |
En dark: el degradado acaba en transparente | Cambiar from-* reinicia to-* en v3 | Repite todas las paradas |
En dark: sigue habiendo un color intermedio | via-* se conserva en v4 | dark:via-none |
accent-* no afecta a <progress> | Preflight desactiva su apariencia nativa | Pseudoelementos |
| El texto blanco no se lee sobre un color claro | Contraste bajo | Texto oscuro, o un paso más alto |
bg-current/5 no genera CSS | Estás en 3.4 | bg-[color-mix(in_srgb,currentColor_5%,transparent)] |
19. Ejercicios
Parte de la tienda EMPRESA: usa clases reales y comprueba el resultado en el navegador.
Ejercicio 1: Etiquetas de estado
Crea cuatro etiquetas de pedido: Entregado (verde), Pendiente (ámbar), Enviado (azul cielo) y Cancelado (rojo). Han de tener un fondo muy suave de su color que se adapte a un fondo oscuro, sin pasos fijos como bg-green-100.
Ver solución
<div class="flex gap-2">
<span class="rounded-full bg-emerald-500/10 px-2.5 py-0.5 text-xs font-semibold text-emerald-700">Entregado</span>
<span class="rounded-full bg-amber-500/10 px-2.5 py-0.5 text-xs font-semibold text-amber-700">Pendiente</span>
<span class="rounded-full bg-sky-500/10 px-2.5 py-0.5 text-xs font-semibold text-sky-700">Enviado</span>
<span class="rounded-full bg-red-500/10 px-2.5 py-0.5 text-xs font-semibold text-red-700">Cancelado</span>
</div>
El truco es el modificador: /10 es translúcido, así que toma lo que hay detrás, y bg-green-100 sería demasiado luminoso en un tema oscuro. El texto usa el paso 700, cuyo contraste es correcto sobre blanco (emerald-700 da 5.36:1).
Ejercicio 2: Botón con degradado
Crea un botón “Añadir al carrito” con un degradado diagonal de índigo a fucsia que se aclare al pasar el ratón. El contraste con el texto ha de ser suficiente.
Ver solución
<a href="#" class="inline-block rounded-lg bg-linear-to-br from-indigo-600 to-fuchsia-600 px-5 py-2.5
font-semibold text-white hover:from-indigo-500 hover:to-fuchsia-500">
Añadir al carrito
</a>
hover: cambia solo --tw-gradient-from y --tw-gradient-to, porque cada clase toca una variable. Texto blanco sobre indigo-600 da 6.46:1. Comprueba también el extremo fucsia: en un degradado, el peor contraste suele estar en uno de los extremos.
Ejercicio 3: Tarjeta con imagen y velo
Crea una tarjeta de 320 × 176 px con la imagen escena.svg de fondo, el nombre del producto en blanco y el precio debajo. El texto ha de leerse bien.
Ver solución
<article class="relative h-44 w-80 overflow-hidden rounded-xl bg-[url(/img/escena.svg)] bg-cover bg-center">
<div class="absolute inset-0 bg-linear-to-t from-black/80 via-black/30 to-transparent"></div>
<div class="absolute inset-x-0 bottom-0 p-4 text-white">
<h3 class="text-lg font-bold">Portátil Gaming 16</h3>
<p class="text-sm text-white/80">Desde 1499 €</p>
</div>
</article>
El degradado va en una capa hija, porque la imagen ya ocupa background-image. via-black/30 hace que la zona oscura suba de forma más gradual. overflow-hidden recorta el velo con las esquinas redondeadas.
Ejercicio 4: Logotipo con degradado
Escribe “Tienda EMPRESA” con un degradado vivo de azul cielo a rosa. Debe verse el color final completo.
Ver solución
<h1 class="w-fit bg-linear-to-r/oklch from-sky-500 to-pink-500 bg-clip-text text-4xl font-extrabold text-transparent">
Tienda EMPRESA
</h1>
Sin w-fit, el degradado se reparte en el ancho total del bloque y el texto se queda en los primeros tonos azules. /oklch mantiene la viveza en el centro.
Ejercicio 5: Gráfico circular
Crea un anillo con un 45 % de color índigo, un 30 % de ámbar y un 25 % de gris, con la palabra “Ventas” en el centro. Los datos son de ejemplo. Usa solo CSS.
Ver solución
<div class="grid size-40 place-items-center rounded-full
bg-[conic-gradient(var(--color-indigo-600)_0_45%,var(--color-amber-400)_0_75%,var(--color-gray-200)_0)]">
<div class="grid size-28 place-items-center rounded-full bg-white text-center text-sm font-bold">Ventas</div>
</div>
Las paradas son acumuladas: el índigo llega hasta 45 %; el ámbar, hasta 75 % (45 + 30), y el gris cubre el resto. 0 significa “donde acabó el anterior”. La caja interior tapa el centro y crea el anillo.
Ejercicio 6: Botón de un solo color
Crea un componente de botón en el que una sola clase cambie el color del texto, el borde y el fondo. Haz dos ejemplos: Guardar (índigo) y Borrar (rojo).
Ver solución
<button class="rounded-lg border border-current/40 bg-current/10 px-3 py-1.5 text-sm font-semibold text-indigo-700">Guardar</button>
<button class="rounded-lg border border-current/40 bg-current/10 px-3 py-1.5 text-sm font-semibold text-red-700">Borrar</button>
border-current/40 y bg-current/10 no dependen de ningún color concreto: toman el del texto. Así, el botón se rediseña cambiando únicamente text-*.
Ejercicio 7: Arreglar un degradado gris
Este degradado sale con el centro gris. Da dos soluciones distintas que no cambien los colores inicial y final.
<div class="h-9 rounded bg-linear-to-r/srgb from-blue-600 to-yellow-300"></div>
Ver solución
<!-- Solución 1: rodear la rueda de color -->
<div class="h-9 rounded bg-linear-to-r/oklch from-blue-600 to-yellow-300"></div>
<!-- Solución 2: añadir una parada intermedia -->
<div class="h-9 rounded bg-linear-to-r from-blue-600 via-emerald-400 to-yellow-300"></div>
La primera cambia el camino y la segunda obliga a pasar por un color. Quitar /srgb también mejora el centro, ya que oklab lo aclara, aunque sigue siendo un tono apagado.
Ejercicio 8: Una marca derivada
Define en @theme un color de marca y dos derivados, uno muy suave y otro oscuro, con color-mix(). Úsalos en una caja con una etiqueta sólida y otra translúcida.
Ver solución
@theme {
--color-marca: oklch(52% 0.17 200);
--color-marca-suave: color-mix(in oklab, var(--color-marca) 12%, white);
--color-marca-oscura: color-mix(in oklab, var(--color-marca) 70%, black);
}
<div class="flex items-center gap-2 rounded-lg bg-marca-suave p-3">
<span class="rounded bg-marca px-3 py-1 text-sm font-semibold text-white">Marca</span>
<span class="rounded border border-marca/40 bg-marca/10 px-3 py-1 text-sm font-semibold text-marca-oscura">Marca suave</span>
</div>
Valores medidos en Chromium: el fondo es oklab(0.942395 -0.0191296 -0.00695954), y el texto oscuro, oklab(0.364 -0.111823 -0.0407004). Si cambias --color-marca, los dos derivados se recalculan solos, y los modificadores /40 y /10 siguen funcionando.
Ejercicio 9: Buscador de la tienda
Crea un formulario con un campo de búsqueda, una casilla y un deslizador que usen el color índigo, y un texto de ayuda con contraste suficiente.
Ver solución
<form class="max-w-sm space-y-3 text-sm accent-indigo-600">
<input type="search" placeholder="Buscar producto"
class="w-full rounded-lg border border-gray-300 px-3 py-2 caret-indigo-600
placeholder:text-gray-500 selection:bg-indigo-600/20">
<label class="flex items-center gap-2"><input type="checkbox" checked> Solo con stock</label>
<label class="flex items-center gap-2">
<input type="range" value="40" class="min-w-0 grow"> <span class="shrink-0">Precio máximo</span>
</label>
</form>
accent-indigo-600 en el <form> se hereda. placeholder:text-gray-500 tiene 4.84:1 sobre blanco, mientras que gray-400 se queda en 2.60:1.

Figura 24. Las soluciones de los ejercicios 1 a 9, compiladas con Tailwind 4.3.3.
Ejercicio 10: Bajar a la LTS
Reescribe este bloque para Tailwind 3.4, con el mismo aspecto.
<section class="relative h-44 overflow-hidden rounded-xl bg-[url(/img/escena.svg)] bg-cover bg-center">
<div class="absolute inset-0 bg-linear-to-r from-indigo-950/90 to-transparent"></div>
<div class="relative p-5 text-white">
<h2 class="w-fit bg-linear-to-r/oklch from-white to-amber-200 bg-clip-text text-2xl font-bold text-transparent">Rebajas</h2>
<span class="mt-2 inline-block rounded-full border border-white/40 bg-current/15 px-2 text-xs">Hasta -30 %</span>
<div class="mt-3 size-10 rounded-full bg-conic from-amber-400 from-75% to-white to-75%"></div>
</div>
</section>
Ver solución
<section class="relative h-44 overflow-hidden rounded-xl bg-[url('/img/escena.svg')] bg-cover bg-center">
<div class="absolute inset-0 bg-gradient-to-r from-indigo-950/90 to-transparent"></div>
<div class="relative p-5 text-white">
<h2 class="w-fit bg-[linear-gradient(to_right_in_oklch,theme(colors.white),theme(colors.amber.200))] bg-clip-text text-2xl font-bold text-transparent">Rebajas</h2>
<span class="mt-2 inline-block rounded-full border border-white/40 bg-[color-mix(in_oklab,currentColor_15%,transparent)] px-2 text-xs">Hasta -30 %</span>
<div class="mt-3 size-10 rounded-full bg-[conic-gradient(theme(colors.amber.400)_75%,theme(colors.white)_0)]"></div>
</div>
</section>
| Original v4 | Equivalente en 3.4 |
|---|---|
bg-linear-to-r | bg-gradient-to-r |
bg-linear-to-r/oklch | Degradado arbitrario in oklch con theme() |
bg-current/15 | color-mix() arbitrario con currentColor |
bg-conic con paradas | bg-[conic-gradient(...)] |

Figura 25. El resultado compilado con Tailwind 3.4.19. El ámbar es algo más apagado, porque amber-400 es #fbbf24 en esa paleta.
Ejercicio 11 (propuesto): Banner de oferta
Crea un banner de ancho completo con motivo repetido (motivo.svg) a 24 px y un velo de degradado horizontal, con una llamada a la acción sobre fondo sólido. Comprueba el contraste del texto en el punto más claro del velo.
Ejercicio 12 (propuesto): Paleta con matiz
Rehaz el caso real de la sección 17 cambiando gray por mauve (o por olive) y el color de acento por un tono que combine. Mide el contraste de cinco pares de color y compáralos con los de gray. Si usas la LTS, añade antes los hexadecimales de la sección 14 a tu configuración.
Resumen
| Concepto | API | Idea clave |
|---|---|---|
| Clase de color | bg-indigo-600, text-*, border-* | Propiedad, familia y paso; la misma paleta en todas partes |
| Paleta | 26 familias, 11 pasos | --color-* en el tema; cambia de valores en v4 |
| OKLCH | oklch(L C H) | Luminosidad, croma y tono, ajustados a la percepción |
| Contraste | WCAG 4.5:1 y 3:1 | Mídelo; un paso no vale igual en todos los colores |
| Opacidad | bg-red-500/50, /37, /(--alfa) | Solo el color, a diferencia de opacity-50 |
| Eliminadas en v4 | bg-opacity-* y familia | Sin error: el fondo queda opaco |
| Color actual | text-current, fill-current, bg-current/5 | Una clase colorea todo el componente |
| Variables | bg-(--marca), bg-(image:--fondo) | Indica el tipo si no es un color |
| Degradado lineal | bg-linear-to-r, bg-linear-65 | bg-gradient-to-r en v3 |
| Paradas | from-*, via-*, to-*, from-20%, via-none | Variables que se combinan; lo omitido es transparente |
| Interpolación | /srgb, /oklab, /oklch, /longer | oklab por defecto; solo cambia el camino |
| Radial y cónico | bg-radial, bg-conic-180, bg-[conic-gradient(...)] | Gráficos con CSS y ruedas de color |
| Imagen | bg-[url(...)], bg-cover, bg-center, bg-no-repeat | bg-* para decoración, <img> para contenido |
| Valores propios | bg-size-[...], bg-position-[...] | bg-[length:...] y bg-[position:...] en v3 |
| Capas | Capa hija o bg-[a,b] | Dos clases de background-image no se suman |
| Recorte | bg-clip-text, bg-clip-padding, bg-origin-* | Texto con degradado: añade text-transparent y w-fit |
| Paletas nuevas | taupe, mauve, mist, olive | Grises con matiz desde 4.2 |
| Mezcla | color-mix(in oklab, a 25%, b), --alpha() | Base del modificador /; deriva colores en @theme |
| Formularios | accent-*, caret-*, selection:, placeholder: | Una clase en el <form>; <progress> necesita pseudoelementos |