Tailwind CSS v3.1: ¿Quieres volverte loco? ¡Vamos, volvámonos locos!

Adam Wathan

Han pasado unos seis meses desde que lanzamos Tailwind CSS v3.0, y aunque hemos estado recopilando muchas pequeñas mejoras en el código base desde entonces, simplemente no teníamos esa característica única todavía que te hace decir "ok, es hora de lanzar la versión".

Luego, un sábado por la noche al azar hace un par de semanas, estaba hablando con Robin en nuestro Discord sobre cómo encontrar una manera de apuntar al elemento html usando :has y una clase más profunda en el documento, y expliqué cómo pensé que se vería si añadiéramos soporte para variantes arbitrarias — algo que he querido abordar durante más de un año:

Adam Wathan: Creo que si hacemos variantes arbitrarias, la sintaxis debería ser exactamente eso, '[html:has(&)]:bg-blue-500'. Siento que eso es bastante flexible, como cualquier cosa que puedas hacer con una variante real también puedes hacerla con una variante arbitraria ya que son lo mismo. '[&>*:not(:first-child)]:pl-4'. Robin: Esto va a romperme el cerebro jaja porque '[html:has(&)]:bg-blue-500' se usaría como un literal dentro del '&'. Eso en combinación con otras variantes... 🤯. Adam Wathan: 😅 será un derrite-cerebros seguro. El CSS sería este lol 'html:has([html:has(&)]:bg-blue-500) { background: blue 500 }'. Robin: exacto jaja. ok, ahora quiero probar eso brb.

Veinte minutos después, Robin tenía una prueba de concepto funcional (¡en seis líneas de código!), y después de otra hora más o menos de Jordan realizando milagros de regex en nuestro motor de detección de clases, nacieron las variantes arbitrarias y tuvimos nuestra característica digna de lanzamiento.

Así que aquí está — ¡Tailwind CSS v3.1! Para una lista completa de cada arreglo y mejora, consulta las notas de la versión, pero aquí están los puntos destacados:

Actualiza tus proyectos instalando la última versión de tailwindcss desde npm:

npm install tailwindcss@latest

O abre un Tailwind Play para jugar con todas las novedades directamente en el navegador.


Tipos TypeScript de primera parte

Ahora estamos enviando tipos para todas nuestras APIs JS con las que trabajas al usar Tailwind, especialmente el archivo tailwind.config.js. Esto significa que obtienes todo tipo de soporte útil del IDE, y hace que sea mucho más fácil hacer cambios en tu configuración sin consultar tanto la documentación.

Para configurarlo, simplemente añade la anotación de tipo sobre la definición de tu configuración:

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
// ...
],
theme: {
extend: {},
},
plugins: [],
};

Si eres un gran nerd de TypeScript, podrías disfrutar husmeando en las definiciones de tipos reales — hay muchas cosas interesantes sucediendo allí para soportar un objeto potencialmente tan complejo.

Soporte integrado para importaciones CSS en la CLI

Si estás usando nuestra herramienta CLI para compilar tu CSS, postcss-import ahora está integrado directamente para que puedas organizar tu CSS personalizado en múltiples archivos sin ninguna configuración adicional.

@import "tailwindcss/base";
@import "./select2-theme.css";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

Si no estás usando nuestra herramienta CLI y en su lugar estás usando Tailwind como un plugin de PostCSS, todavía necesitarás instalar y configurar postcss-import tú mismo, tal como lo haces con autoprefixer, pero si estás usando nuestra herramienta CLI, esto funcionará totalmente ahora.

Esto es especialmente útil si estás usando nuestra CLI independiente y no quieres instalar ninguna dependencia de node en absoluto.

Cambiar la opacidad del color al usar la función theme

No creo que mucha gente sepa esto, pero Tailwind expone una función theme() a tus archivos CSS que te permite obtener valores de tu archivo de configuración — convirtiéndolos en una especie de variables que puedes reutilizar.

select2-theme.css
.select2-dropdown {
border-radius: theme(borderRadius.lg);
background-color: theme(colors.gray.100);
color: theme(colors.gray.900);
}
/* ... */

Una limitación, sin embargo, era que no podías ajustar el canal alfa de ningún color que obtuvieras de esta manera. Así que en v3.1 hemos añadido soporte para usar una sintaxis de barra inclinada para ajustar la opacidad, como puedes hacer con las funciones de color CSS modernas rgb y hsl:

select2-theme.css
.select2-dropdown {
border-radius: theme(borderRadius.lg);
background-color: theme(colors.gray.100 / 50%);
color: theme(colors.gray.900);
}
/* ... */

Hemos hecho que esto funcione también con la función theme en tu archivo tailwind.config.js:

tailwind.config.js
module.exports = {
content: [
// ...
],
theme: {
extend: {
colors: ({ theme }) => ({
primary: theme("colors.blue.500"),
"primary-fade": theme("colors.blue.500 / 75%"),
}),
},
},
plugins: [],
};

Incluso puedes usar estas cosas en valores arbitrarios, lo cual es bastante salvaje — honestamente sorprendentemente útil para gradientes personalizados extraños y cosas así:

<div class="bg-[image:linear-gradient(to_right,theme(colors.red.500)_75%,theme(colors.red.500/25%))]">
<!-- ... -->
</div>

Cualquier cosa para evitar editar un archivo CSS, ¿verdad?

Configuración de color de variable CSS más fácil

Si te gusta definir y configurar tus colores como variables CSS, probablemente tengas algún boilerplate horrible como este en tu archivo tailwind.config.js ahora mismo:

tailwind.config.js
function withOpacityValue(variable) {
return ({ opacityValue }) => {
if (opacityValue === undefined) {
return `rgb(var(${variable}))`;
}
return `rgb(var(${variable}) / ${opacityValue})`;
};
}
module.exports = {
theme: {
colors: {
primary: withOpacityValue("--color-primary"),
secondary: withOpacityValue("--color-secondary"),
// ...
},
},
};

Hemos hecho esto mucho menos horrible en v3.1 añadiendo soporte para definir tus colores con una cadena de formato en lugar de tener que usar una función:

tailwind.config.js
module.exports = {
theme: {
colors: {
primary: "rgb(var(--color-primary) / <alpha-value>)",
secondary: "rgb(var(--color-secondary) / <alpha-value>)",
// ...
},
},
};

En lugar de escribir una función que recibe ese argumento opacityValue, puedes simplemente escribir una cadena con un marcador de posición <alpha-value>, y Tailwind reemplazará ese marcador de posición con el valor alfa correcto basado en la utilidad.

Si no has visto nada de esto antes, consulta nuestra documentación actualizada de Uso de variables CSS para obtener más detalles.

Utilidades de espaciado de borde

Hemos añadido un nuevo conjunto de utilidades para la propiedad border-spacing, para que puedas controlar el espacio entre los bordes de la tabla al usar bordes separados:

EstadoCiudad
IndianaIndianápolis
OhioColumbus
MichiganDetroit
<table class="border-separate border-spacing-2 ...">
<thead>
<tr>
<th class="border border-slate-300 ...">Estado</th>
<th class="border border-slate-300 ...">Ciudad</th>
</tr>
</thead>
<tbody>
<tr>
<td class="border border-slate-300 ...">Indiana</td>
<td class="border border-slate-300 ...">Indianápolis</td>
</tr>
<!-- ... -->
</tbody>
</table>

Sé lo que estás pensando — "Nunca en mi vida he querido construir una tabla que se vea así..." — ¡pero escucha por un segundo!

Una situación en la que esto es realmente súper útil es al construir una tabla con una fila de encabezado fija (sticky) y quieres un borde inferior persistente debajo de los encabezados:

Desplázate por esta tabla para ver la fila de encabezado fija en acción

NombreRol
Courtney HenryAdmin
Tom CookMiembro
Whitney FrancisAdmin
Leonard KrasnerPropietario
Floyd MilesMiembro
Emily SelmanMiembro
Kristin WatsonAdmin
Emma DorseyMiembro
Alicia BellAdmin
Jenny WilsonPropietario
Anna RobertsMiembro
Benjamin RusselMiembro
Jeffrey WebbAdmin
Kathryn MurphyMiembro
<table class="border-separate border-spacing-0">
<thead class="bg-gray-50">
<tr>
<th class="sticky top-0 z-10 border-b border-gray-300 ...">Nombre</th>
<th class="sticky top-0 z-10 border-b border-gray-300 ...">Email</th>
<th class="sticky top-0 z-10 border-b border-gray-300 ...">Rol</th>
</tr>
</thead>
<tbody class="bg-white">
<tr>
<td class="border-b border-gray-200 ...">Courtney Henry</td>
<td class="border-b border-gray-200 ...">courtney.henry@example.com</td>
<td class="border-b border-gray-200 ...">Admin</td>
</tr>
<!-- ... -->
</tbody>
</table>

Pensarías que podrías usar border-collapse aquí, ya que en realidad no quieres ningún espacio entre los bordes, pero te equivocarías. Sin border-separate y border-spacing-0, el borde se desplazará en lugar de quedarse fijo debajo de los encabezados. CSS es divertido, ¿no?

Consulta la documentación de espaciado de borde para obtener más detalles.

Variantes Enabled y optional

Hemos añadido nuevas variantes para las pseudo-clases :enabled y :optional, que apuntan a los elementos de formulario cuando están, bueno, habilitados y opcionales.

"Pero Adam, ¿por qué necesitaría esto alguna vez? Habilitado y opcional ni siquiera son estados, son los predeterminados. ¿Acaso haces sitios web?"

Ay, eso duele porque es verdad — prácticamente solo escribo correos electrónicos y respondo las mismas preguntas una y otra vez en GitHub ahora.

Pero mira este ejemplo de botón deshabilitado:

<button type="button" class="bg-indigo-500 hover:bg-indigo-400 disabled:opacity-75 ..." disabled>Procesando...</button>

¿Notas cómo cuando pasas el cursor sobre el botón, el fondo todavía cambia de color aunque esté deshabilitado? Antes de esta versión, normalmente arreglarías eso así:

<button
type="button"
class="bg-indigo-500 hover:bg-indigo-400 disabled:opacity-75 disabled:hover:bg-indigo-500 ..."
disabled
>
Procesando...
</button>

Pero con el nuevo modificador enabled, puedes escribirlo así en su lugar:

<button type="button" class="bg-indigo-500 hover:enabled:bg-indigo-400 disabled:opacity-75 ..." disabled>
Procesando...
</button>

En lugar de anular el color de hover volviendo al color predeterminado cuando el botón está deshabilitado, combinamos las variantes hover y enabled para simplemente no aplicar los estilos de hover cuando el botón está deshabilitado en primer lugar. ¡Creo que eso es mejor!

Aquí hay un ejemplo que combina el nuevo modificador optional con nuestras características de estado de hermano para ocultar un pequeño aviso "Requerido" para los campos que no son requeridos:

Requerido
Requerido
<form>
<div>
<label for="email" ...>Email</label>
<div>
<input required class="peer ..." id="email" />
<div class="peer-optional:hidden ...">Requerido</div>
</div>
</div>
<div>
<label for="name" ...>Nombre</label>
<div>
<input class="peer ..." id="name" />
<div class="peer-optional:hidden ...">Requerido</div>
</div>
</div>
<!-- ... -->
</form>

Esto te permite usar el mismo marcado para todos tus grupos de formularios y dejar que CSS maneje todo el renderizado condicional por ti en lugar de manejarlo tú mismo. ¡Bastante ingenioso!

Variantes Prefers-contrast

¿Sabías que hay una media query prefers-contrast? Bueno, existe, y ahora Tailwind la soporta de forma predeterminada.

Usa las nuevas variantes contrast-more y contrast-less para modificar tu diseño cuando el usuario ha solicitado más o menos contraste, generalmente a través de una preferencia de accesibilidad del sistema operativo como "Aumentar contraste" en macOS.

Intenta emular `prefers-contrast: more` en tus herramientas de desarrollador para ver los cambios

Necesitamos esto para robar tu identidad.

<form>
<label class="block">
<span class="block text-sm font-medium text-slate-700">Número de Seguro Social</span>
<input
class="border-slate-200 placeholder-slate-400 contrast-more:border-slate-400 contrast-more:placeholder-slate-500"
/>
<p class="mt-2 text-sm text-slate-600 opacity-10 contrast-more:opacity-100">Necesitamos esto para robar tu identidad.</p>
</label>
</form>

Escribí alguna documentación para esto, pero honestamente escribí más aquí que allí.

Estilizar backdrops de diálogo nativos

Hay un elemento HTML <dialog> bastante nuevo](https://developer.mozilla.org/es/docs/Web/HTML/Element/dialog) con un soporte de navegador sorprendentemente decente con el que vale la pena jugar si te gusta vivir al límite.

Los diálogos tienen este nuevo pseudo-elemento ::backdrop que se renderiza mientras el diálogo está abierto, y Tailwind CSS v3.1 añade un nuevo modificador backdrop que puedes usar para estilizar a este bebé:

<dialog class="backdrop:bg-slate-900/50 ...">
<form method="dialog">
<!-- ... -->
<button value="cancel">Cancelar</button>
<button>Enviar</button>
</form>
</dialog>

Recomiendo leer la documentación de MDN sobre Dialog si quieres profundizar más en esto — es algo emocionante pero hay mucho que saber.

Valores arbitrarios pero para variantes

Ok, así que este es el verdadero punto culminante para mí — ¿sabes cómo te damos la API addVariant para crear tus propias variantes personalizadas?

tailwind.config.js
const plugin = require("tailwindcss/plugin");
module.exports = {
// ...
plugins: [
plugin(function ({ addVariant }) {
addVariant("third", "&:nth-child(3)");
}),
],
};

...¿y sabes cómo tenemos valores arbitrarios para usar cualquier valor que quieras con una utilidad directamente en tu HTML?

<!--] -->
<div class="top-[117px]">
<!-- ... -->
</div>

Bueno, Tailwind CSS v3.1 introduce variantes arbitrarias, permitiéndote crear tus propias variantes ad hoc directamente en tu HTML:

<div class="[&:nth-child(3)]:py-0">
<!-- ... -->
</div>

Esto es súper útil para variantes que de alguna manera parecen necesitar ser parametrizadas, por ejemplo, añadir un estilo si el navegador soporta una característica CSS específica usando una consulta @supports:

<div
class="bg-white [@supports(backdrop-filter:blur(0))]:bg-white/50 [@supports(backdrop-filter:blur(0))]:backdrop-blur"
>
<!-- ... -->
</div>

Incluso puedes usar esta característica para apuntar a elementos hijos con variantes arbitrarias como [&>*]:

  • Kristen Ramos

    kristen.ramos@example.com

  • Floyd Miles

    floyd.miles@example.com

  • Courtney Henry

    courtney.henry@example.com

<ul role="list" class="space-y-4 [&>*]:rounded-lg [&>*]:bg-white [&>*]:p-4 [&>*]:shadow">
<li class="flex">
<img class="h-10 w-10 rounded-full" src="..." alt="" />
<div class="ml-3 overflow-hidden">
<p class="text-sm font-medium text-slate-900">Kristen Ramos</p>
<p class="truncate text-sm text-slate-500">kristen.ramos@example.com</p>
</div>
</li>
<!-- ... -->
</ul>

Incluso puedes estilizar el primer p dentro del div en el segundo li hijo pero solo en hover:

Intenta pasar el cursor sobre el texto 'Floyd Miles'

  • Kristen Ramos

    kristen.ramos@example.com

  • Floyd Miles

    floyd.miles@example.com

  • Courtney Henry

    courtney.henry@example.com

<ul
role="list"
class="space-y-4 [&>*]:rounded-lg [&>*]:bg-white [&>*]:p-4 [&>*]:shadow hover:[&>li:nth-child(2)>div>p:first-child]:text-indigo-500"
>
<!-- ... -->
<li class="flex">
<img class="h-10 w-10 rounded-full" src="..." alt="" />
<div class="ml-3 overflow-hidden">
<p class="text-sm font-medium text-slate-900">Floyd Miles</p>
<p class="truncate text-sm text-slate-500">floyd.miles@example.com</p>
</div>
</li>
<!-- ... -->
</ul>

Ahora, deberías hacer esto? Probablemente no muy a menudo, pero honestamente puede ser una vía de escape bastante útil cuando intentas estilizar HTML que no puedes cambiar directamente. Es un cuchillo afilado, pero los mejores chefs no preparan comida con tijeras de seguridad.

Juega un poco con ellas y apuesto a que encontrarás que son una gran herramienta cuando la situación lo requiere. Las estamos usando en un par de puntos complicados en estas nuevas plantillas de sitio web en las que estamos trabajando y la experiencia es mucho más agradable que crear una clase personalizada.


¡Así que eso es Tailwind CSS v3.1! Es solo un cambio de versión menor, así que no hay cambios que rompan la compatibilidad y deberías poder actualizar tu proyecto simplemente instalando la última versión:

npm install tailwindcss@latest

Para la lista completa de cambios, incluyendo correcciones de errores y algunas mejoras menores de las que no hablé aquí, profundiza en las notas de la versión en GitHub.

Ya tengo un montón de ideas para Tailwind CSS v3.2 (¡quizás incluso sombras de texto finalmente?!), pero ahora mismo estamos trabajando duro para llevar estas nuevas plantillas de sitio web a la línea de meta. ¡Busca otra actualización sobre ese tema en la próxima semana o dos!

Recibe todas nuestras actualizaciones directamente en tu bandeja de entrada.
Suscríbete a nuestro boletín.

Copyright © 2025 Tailwind Labs Inc.·Política de Marca Registrada