En esta página
Transiciones y animaciones con Tailwind
Transiciones y animaciones con Tailwind
El movimiento es un componente esencial del diseño moderno. Las transiciones suaves y las animaciones bien ejecutadas hacen que una interfaz se sienta pulida y profesional. Tailwind proporciona utilidades para controlar transiciones CSS y animaciones predefinidas, además de herramientas para crear animaciones personalizadas con @theme.
Transiciones CSS
La clase `transition`
transition es la clase base que activa transiciones en las propiedades más comunes:
<!-- transition incluye: color, background-color, border-color,
text-decoration-color, fill, stroke, opacity, box-shadow,
transform, filter y backdrop-filter -->
<button class="bg-blue-600 hover:bg-blue-700 transition">
Botón con transición
</button>Variantes específicas de transición
<!-- Solo propiedad color (colores de texto, fondo, borde) -->
<button class="hover:bg-blue-700 hover:text-white transition-colors">...</button>
<!-- Solo opacity -->
<div class="opacity-0 hover:opacity-100 transition-opacity">...</div>
<!-- Solo transform (scale, rotate, translate) — más eficiente -->
<img class="hover:scale-110 transition-transform" src="img.jpg" alt="" />
<!-- Solo box-shadow -->
<div class="shadow-md hover:shadow-xl transition-shadow">...</div>
<!-- Todas las propiedades (costoso, úsalo con cuidado) -->
<div class="hover:bg-blue-500 hover:scale-105 hover:shadow-lg transition-all">...</div>
<!-- Personalizado: solo las propiedades que necesitas -->
<div class="transition-[transform,opacity] hover:scale-105 hover:opacity-100">...</div>Duración de la transición
<div class="transition-colors duration-75">Muy rápida — 75ms</div>
<div class="transition-colors duration-100">100ms</div>
<div class="transition-colors duration-150">150ms (default)</div>
<div class="transition-colors duration-200">200ms</div>
<div class="transition-colors duration-300">300ms — suave</div>
<div class="transition-colors duration-500">500ms — lenta</div>
<div class="transition-colors duration-700">700ms — muy lenta</div>
<div class="transition-colors duration-1000">1000ms — 1 segundo</div>Regla general: usa duration-150 o duration-200 para interacciones del usuario (hover, focus), y duration-300 o más para elementos que se muestran/ocultan.
Función de timing (easing)
<div class="transition ease-linear"> Velocidad constante</div>
<div class="transition ease-in"> Empieza lento, termina rápido</div>
<div class="transition ease-out"> Empieza rápido, termina lento</div>
<div class="transition ease-in-out"> Lento al inicio y al final</div>Para entradas de elementos (appear), ease-out se siente más natural. Para salidas (disappear), ease-in. Para movimiento de objetos físicos, ease-in-out.
Delay de transición
<div class="transition-all duration-300 delay-0">Sin delay</div>
<div class="transition-all duration-300 delay-75">75ms de espera</div>
<div class="transition-all duration-300 delay-150">150ms de espera</div>
<div class="transition-all duration-300 delay-300">300ms de espera</div>
<div class="transition-all duration-300 delay-500">500ms de espera</div>El delay es excelente para crear efectos de entrada escalonados:
<!-- Tarjetas que aparecen en cascada -->
<div class="flex flex-col gap-4">
<div class="opacity-0 translate-y-4 animate-slide-up delay-0">Tarjeta 1</div>
<div class="opacity-0 translate-y-4 animate-slide-up delay-100">Tarjeta 2</div>
<div class="opacity-0 translate-y-4 animate-slide-up delay-200">Tarjeta 3</div>
</div>Transformaciones CSS
Las transformaciones trabajan conjuntamente con las transiciones:
Translate (desplazamiento)
<!-- Desplazamiento en X -->
<div class="translate-x-0 hover:translate-x-1">→ Pequeño deslizamiento</div>
<div class="-translate-x-full">Completamente fuera por la izquierda</div>
<!-- Desplazamiento en Y -->
<div class="translate-y-0 hover:-translate-y-2">↑ Sube al hacer hover</div>
<div class="translate-y-full">Completamente fuera por abajo</div>
<!-- Drawer/panel deslizante -->
<div
class="fixed right-0 top-0 h-full w-80 bg-white shadow-2xl z-50
translate-x-full transition-transform duration-300
data-[open=true]:translate-x-0"
data-open="false"
>
Panel lateral
</div>Scale
<div class="scale-75">Reducido al 75%</div>
<div class="scale-100">Tamaño normal</div>
<div class="scale-110 hover:scale-125 transition-transform">Crece en hover</div>
<div class="scale-x-110">Solo eje X</div>
<div class="scale-y-90">Solo eje Y</div>Rotate
<svg class="w-4 h-4 rotate-0 transition-transform
group-open:rotate-180">▼</svg>
<!-- Patrón para accordions -->
<details class="group">
<summary class="flex items-center justify-between cursor-pointer p-4">
<span>¿Cuánto dura el curso?</span>
<svg
class="w-5 h-5 text-gray-400 rotate-0 group-open:rotate-180
transition-transform duration-200"
viewBox="0 0 20 20" fill="currentColor"
>
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"/>
</svg>
</summary>
<div class="px-4 pb-4 text-gray-600">
El curso tiene una duración estimada de 12 horas.
</div>
</details>Animaciones predefinidas
Tailwind incluye 4 animaciones listas para usar:
animate-spin
<!-- Spinner de carga clásico -->
<div
class="w-8 h-8 rounded-full border-4 border-gray-200 border-t-blue-600
animate-spin"
role="status"
aria-label="Cargando..."
></div>
<!-- Spinner con texto -->
<div class="flex items-center gap-3">
<div class="w-5 h-5 border-2 border-current border-t-transparent
rounded-full animate-spin text-blue-600"></div>
<span class="text-gray-600 text-sm">Cargando contenido...</span>
</div>animate-ping
<!-- Indicador de estado en tiempo real -->
<div class="relative flex h-3 w-3">
<div
class="absolute inline-flex h-full w-full rounded-full
bg-green-400 opacity-75 animate-ping"
></div>
<div class="relative inline-flex h-3 w-3 rounded-full bg-green-500"></div>
</div>
<!-- Notificación en icono -->
<div class="relative inline-block">
<svg class="w-6 h-6 text-gray-600"><!-- icono campana --></svg>
<span class="absolute top-0 right-0 block h-2 w-2">
<span class="animate-ping absolute inline-flex h-full w-full
rounded-full bg-red-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-red-500"></span>
</span>
</div>animate-pulse
<!-- Skeleton loader para tarjeta -->
<div class="bg-white rounded-xl p-6 shadow-sm space-y-4">
<!-- Imagen skeleton -->
<div class="bg-gray-200 rounded-lg h-40 animate-pulse"></div>
<!-- Texto skeleton -->
<div class="space-y-2">
<div class="bg-gray-200 rounded h-4 w-3/4 animate-pulse"></div>
<div class="bg-gray-200 rounded h-4 w-1/2 animate-pulse"></div>
<div class="bg-gray-200 rounded h-4 w-5/6 animate-pulse"></div>
</div>
<!-- Botón skeleton -->
<div class="bg-gray-200 rounded-lg h-10 w-32 animate-pulse"></div>
</div>animate-bounce
<!-- Flecha de scroll down -->
<div class="flex justify-center pt-8 motion-safe:animate-bounce">
<svg
class="w-6 h-6 text-gray-400"
fill="none" stroke="currentColor" viewBox="0 0 24 24"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7"/>
</svg>
</div>Animaciones personalizadas con @theme
Para animaciones propias, define los @keyframes y agrégalos a @theme:
/* styles.css */
@import "tailwindcss";
/* Definir los keyframes */
@keyframes fade-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes fade-out {
from { opacity: 1; transform: translateY(0); }
to { opacity: 0; transform: translateY(8px); }
}
@keyframes slide-in-right {
from { opacity: 0; transform: translateX(24px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes scale-in {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
@keyframes shimmer {
from { background-position: -200% 0; }
to { background-position: 200% 0; }
}
/* Registrar en @theme para generar clases animate-* */
@theme {
--animate-fade-in: fade-in 0.3s ease-out both;
--animate-fade-out: fade-out 0.2s ease-in both;
--animate-slide-in-right: slide-in-right 0.3s ease-out both;
--animate-scale-in: scale-in 0.2s ease-out both;
--animate-shimmer: shimmer 2s linear infinite;
}<!-- Uso de animaciones personalizadas -->
<div class="animate-fade-in">Aparece con fade</div>
<div class="animate-slide-in-right">Desliza desde la derecha</div>
<div class="animate-scale-in">Escala desde el centro</div>
<!-- Shimmer para skeletons más elegantes -->
<div
class="animate-shimmer h-4 rounded
bg-[linear-gradient(90deg,#e5e7eb_25%,#f3f4f6_50%,#e5e7eb_75%)]
bg-[length:200%_100%]"
></div>motion-safe y motion-reduce
Siempre es buena práctica envolver las animaciones con variantes de preferencia de movimiento:
<!-- Solo anima si el usuario NO tiene reducción de movimiento -->
<div class="motion-safe:animate-bounce motion-reduce:opacity-75">
Indicador
</div>
<!-- Versión alternativa estática para motion-reduce -->
<button
class="bg-blue-600 text-white px-4 py-2 rounded
motion-safe:hover:scale-105 motion-safe:active:scale-95
motion-safe:transition-transform
motion-reduce:hover:bg-blue-700 motion-reduce:transition-colors"
>
Botón accesible
</button>Combinación de transición + transformación: botón avanzado
<button
type="button"
class="group relative overflow-hidden
bg-gradient-to-r from-blue-500 to-blue-600
text-white font-semibold px-8 py-4 rounded-2xl
shadow-lg shadow-blue-500/30
hover:shadow-xl hover:shadow-blue-500/40
active:scale-95
transition-all duration-200
focus-visible:ring-2 focus-visible:ring-blue-400 focus-visible:ring-offset-2"
>
<!-- Efecto shimmer en hover -->
<span
class="absolute inset-0 bg-gradient-to-r from-transparent via-white/20 to-transparent
-translate-x-full group-hover:translate-x-full
transition-transform duration-700"
></span>
<!-- Texto del botón -->
<span class="relative">Empezar ahora →</span>
</button>Resumen
Para transiciones: usa transition-colors, transition-transform o transition-all según lo que necesites animar, con duration-150 a duration-300 para interacciones y ease-out para entradas. Para animaciones: las cuatro incluidas (spin, ping, pulse, bounce) cubren los casos más comunes. Para animaciones propias, define @keyframes y registra en @theme con --animate-*. Siempre incluye motion-reduce: para accesibilidad.
<!-- transition aplica a color, background-color, border-color,
text-decoration-color, fill, stroke, opacity,
box-shadow, transform y filter -->
<button
class="bg-blue-600 text-white px-6 py-3 rounded-xl font-semibold
hover:bg-blue-700 hover:scale-105 hover:shadow-lg
active:scale-95
transition-all duration-200 ease-out"
>
Botón con transición
</button>
<!-- Transición de solo transform (más eficiente) -->
<div class="hover:scale-110 transition-transform duration-300 ease-in-out">
Escala suave
</div>
<!-- Transición de opacidad para fade -->
<div
class="opacity-0 hover:opacity-100
transition-opacity duration-500"
>
Fade in
</div>
<!-- Transición con delay -->
<div
class="translate-y-4 opacity-0
group-hover:translate-y-0 group-hover:opacity-100
transition-all duration-300 delay-150"
>
Aparece con retraso
</div>
Inicia sesión para guardar tu progreso