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-500 no es el mismo rojo en v3 y en v4
  • Aplicar opacidad con /50, distinguirla de opacity-50 y saber qué CSS produce
  • Aprovechar currentColor para 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-* y to-*
  • 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-* y bg-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-* y caret-*, 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.css sin 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.

Desglose de la clase hover:bg-indigo-600/50 en variante, propiedad, familia, paso y modificador de 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.

Cuadrícula de 26 familias de color por 11 pasos, del 50 casi blanco al 950 casi negro

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-500 es #ef4444 en 3.4 y #fb2c36 en 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 en theme.extend.colors para 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:

Tres barras: luminosidad de negro a blanco, croma de gris a intenso y tono como rueda de color

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.

Dos filas de seis colores: en HSL el azul es mucho más oscuro que el amarillo; en OKLCH todos parecen igual de claros

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. oklch puede 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.

Nueve muestras divididas: a la izquierda el color de v3 y a la derecha el de v4, con sus hexadecimales

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>

Cinco cajas de color índigo con opacidad decreciente sobre una imagen, y dos cajas blancas que comparan bg-white/50 con opacity-50

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/50 aplica 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) /37 no 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-* y placeholder-opacity-*; v4 las elimina. Si usas la LTS: puedes seguir usándolas, aunque es mejor escribir ya bg-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:

Tres alertas en verde, ámbar y rojo cuyo icono, borde y fondo derivan del color del texto

Figura 7. Tres alertas que solo se diferencian en una clase.

📘 Concepto: fill-current es la forma estándar de colorear un icono SVG inline. Así, un icono dentro de un enlace cambia de color con él en hover: sin tocar el SVG. Las imágenes cargadas con <img> no heredan color, 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/5 y border-current/30 no 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 con color-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ágenes bg-[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-r e interpola en sRGB; v4 la renombra a bg-linear-to-r e interpola en Oklab. Si usas la LTS: escribe bg-gradient-to-r, bg-gradient-to-tl… y deja igual from-*, via-* y to-*, 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).

Diez degradados de índigo a cian con las ocho direcciones y dos ángulos

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>

Seis barras de degradado: dos colores, tres colores, con posiciones, corte brusco y dos que acaban o empiezan en transparente

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% y to-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.

Las clases bg-linear-to-r, from, via y to rellenan variables que forman --tw-gradient-stops y se usan en background-image

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 existe via-none: en v3 el propio reinicio ya elimina el via.

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 un bg-blue-600 debajo.

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>

Siete barras del mismo degradado azul a amarillo con distinto modificador: srgb sale gris, oklab algo más claro, oklch pasa por el verde y longer por el rosa

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, /decreasing coincide con /oklch.
  • El camino largo sube de 264 a 360 y sigue hasta 100, pasando por morados, rosas y naranjas. Por eso /increasing coincide 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 /oklch para 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 /srgb si 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:

Tres barras compiladas con Tailwind 3.4 en sRGB, oklab y oklch, y seis cuadrados de prueba con radial, cónico, imagen repetida, posición, color propio y color-mix

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-* y to-* funcionan dentro de un valor arbitrario: bg-[radial-gradient(var(--tw-gradient-stops))] y bg-[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>

Ocho ejemplos: cuatro gradientes radiales y cuatro cónicos, incluida una rueda de color

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-[...] y bg-radial-[...] tienen dos usos. Si hay clases from-* o to-*, el valor es lo que va antes de los colores, como from_90deg. Si no las hay, el valor se usa como lista completa, porque genera conic-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í uso bg-[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')].

Doce cajas con distintas combinaciones de tamaño, repetición y posición de imagen de fondo

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-bottom y bg-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] y bg-[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> con object-cover si la imagen es contenido, como la foto de un producto. Lleva alt, 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>

Tres tarjetas: sin velo, con una capa hija y con dos capas en un valor arbitrario

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.

Tres cajas con recorte de fondo distinto, tres cajas con distinto origen y un título con degradado

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-text recorta el fondo con la forma de las letras.
  • text-transparent deja ver ese fondo. Sin ella, el texto normal lo tapa y no se aprecia nada.
  • w-fit ajusta el ancho al texto. Un encabezado es un bloque que ocupa toda la línea, y el degradado se reparte en ese ancho: sin w-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.colors del fichero tailwind.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.

Seis filas de grises con matiz: stone junto a taupe y mauve, y slate junto a mist y olive

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 da rgb(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>

Cinco tonos de índigo mezclados con blanco, y dos mezclas de azul y amarillo en sRGB y Oklab

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), sin color-mix() el fondo se queda opaco, y lo mismo pasa con bg-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>

Formulario con casilla, radio y deslizador en índigo, una casilla en rosa, cursor rosa y un texto de ayuda en índigo

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:

Campo de texto con la palabra Portátil seleccionada sobre fondo ámbar

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>

Dos barras de progreso: la primera verde con accent, la segunda índigo y redondeada con pseudoelementos

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>

Portada con banner de rebajas sobre imagen y tres tarjetas de producto en tema claro

Figura 22. La portada en tema claro.

La misma portada en tema oscuro, con las tarjetas casi negras y las etiquetas más claras

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/90 se oscurece a la izquierda, donde va el texto, y to-transparent deja ver la imagen a la derecha. relative en el contenido lo sitúa por encima de la capa absolute.
  • El botón usa texto oscuro. Ya vimos que text-white sobre ámbar da 1.72:1, y text-gray-950 da 11.69:1.
  • hover: cambia solo dos variables. El degradado no se reescribe: basta con cambiar from y to.
  • La etiqueta funciona en los dos temas. bg-emerald-500/10 es translúcido y se adapta a lo que tiene detrás, de modo que solo cambia el color del texto.
  • dark:border-white/10 es 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.

Soluciones de los ejercicios 1 a 9

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(...)]

Resultado compilado con Tailwind 3.4: banner con título en degradado, etiqueta y círculo cónico

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