Svelte Transitions: Animaciones Fluidas para una Interfaz de Usuario Dinámica ✨
Este tutorial te guiará a través del fascinante mundo de las transiciones en Svelte, una característica poderosa que permite crear animaciones fluidas y significativas en tu interfaz de usuario. Aprenderás a usar las transiciones integradas y a crear las tuyas propias, transformando la experiencia de tus usuarios.
Svelte se ha ganado un lugar en el corazón de muchos desarrolladores gracias a su reactividad intrínseca y su compilación a código JavaScript vanilla, lo que resulta en aplicaciones ultrarrápidas y ligeras. Pero no solo es rápido y eficiente, también ofrece herramientas increíbles para mejorar la experiencia de usuario, y las Transiciones son una de las más destacadas.
Las transiciones de Svelte permiten animar la entrada y salida de elementos del DOM de una manera declarativa y elegante. Esto significa que puedes añadir ese toque profesional y dinámico a tus componentes sin tener que lidiar con librerías de animación complejas o manipular directamente el DOM. ¡Vamos a sumergirnos en cómo hacer que tus aplicaciones cobren vida!
¿Qué son las Svelte Transitions? 🚀
En el contexto de Svelte, una transición es una animación que ocurre cuando un elemento se añade o se elimina del DOM. Imagina un elemento que se desvanece suavemente al ser eliminado, o un menú que se desliza elegantemente al aparecer. Esas son las Svelte Transitions en acción.
Svelte maneja estas animaciones de forma eficiente y te permite definirlas directamente en el markup de tus componentes, lo que las hace increíblemente fáciles de usar y mantener. No necesitas lifecycle hooks complejos ni gestores de estado adicionales para orquestarlas; Svelte lo hace por ti.
El Modelo Mental de las Transiciones
Piensa en las transiciones como una forma de dar vida a tus componentes. Cuando un componente aparece, no solo "aparece", sino que puede "entrar" con un efecto. Cuando desaparece, no solo "desaparece", sino que puede "salir" con otro efecto. Esta distinción entre entrada (in) y salida (out) es clave y Svelte te permite usar transiciones diferentes para cada fase o una transición combinada (transition).
Primeros Pasos: Usando Transiciones Integradas 🛠️
Svelte viene con un conjunto de transiciones predefinidas que son muy útiles para empezar. Son fáciles de aplicar y cubren la mayoría de los casos de uso básicos. Las más comunes son fade, slide, blur, scale, draw y fly.
Para usar una transición, simplemente añade el atributo transition:nombreDeTransicion (o in:nombreDeTransicion y out:nombreDeTransicion) a cualquier elemento HTML o componente Svelte que esté sujeto a ser montado o desmontado condicionalmente. Esto suele ocurrir dentro de un bloque {#if ...}.
fade: Desvanecimiento Simple
La transición fade es la más sencilla: el elemento aparece y desaparece atenuándose gradualmente. Es ideal para avisos, modales o cualquier contenido que necesite una entrada/salida suave.
<script>
let show = false;
</script>
<button on:click={() => (show = !show)}>Toggle Fade</button>
{#if show}
<p transition:fade>
¡Este texto se desvanece al aparecer y desaparecer!
</p>
{/if}
slide: Deslizamiento Lateral
La transición slide hace que un elemento se deslice hacia arriba o hacia abajo. Es perfecta para menús desplegables, barras laterales o listas que se expanden/contraen.
<script>
let showMenu = false;
</script>
<button on:click={() => (showMenu = !showMenu)}>Toggle Menu</button>
{#if showMenu}
<ul transition:slide>
<li>Elemento 1</li>
<li>Elemento 2</li>
<li>Elemento 3</li>
</ul>
{/if}
blur: Desenfoque
blur añade un efecto de desenfoque al elemento al aparecer y desaparecer. Puede ser muy útil para destacar o suavizar la entrada de contenido.
<script>
let showCard = false;
</script>
<button on:click={() => (showCard = !showCard)}>Toggle Card</button>
{#if showCard}
<div transition:blur>
<h2>Tarjeta con efecto Blur</h2>
<p>Este contenido aparece con un desenfoque suave.</p>
</div>
{/if}
scale: Escalado
scale hace que un elemento crezca o se encoja al aparecer/desaparecer. Funciona bien para botones, iconos o imágenes que necesiten un efecto de zoom.
<script>
let showImage = false;
</script>
<button on:click={() => (showImage = !showImage)}>Toggle Image</button>
{#if showImage}
<img src="https://via.placeholder.com/150" alt="Placeholder" transition:scale />
{/if}
fly: Desplazamiento y Opacidad
fly es una combinación de fade y slide, donde el elemento se desplaza desde una posición inicial y cambia su opacidad. Puedes especificar la distancia (x, y) y la opacidad (opacity).
<script>
let showNotification = false;
</script>
<button on:click={() => (showNotification = !showNotification)}>Mostrar Notificación</button>
{#if showNotification}
<div transition:fly={{ y: -50, duration: 500, delay: 200 }} class="notification">
¡Notificación importante!
</div>
{/if}
<style>
.notification {
background-color: #4CAF50;
color: white;
padding: 15px;
border-radius: 5px;
margin-top: 20px;
position: absolute;
right: 20px;
top: 20px;
}
</style>
draw: Animando SVG ✨
draw es una transición fascinante que permite animar el trazado de elementos SVG (como path o line). Es ideal para introducir gráficos de forma dramática.
<script>
let showPath = false;
</script>
<button on:click={() => (showPath = !showPath)}>Dibujar Path</button>
{#if showPath}
{/if}
<div class="callout important">🔥 <strong>Importante:</strong> Para que `draw` funcione correctamente, el elemento SVG debe tener atributos `stroke-dasharray` y `stroke-dashoffset` calculables por Svelte. Svelte los gestiona automáticamente, pero es bueno saber qué sucede "bajo el capó".</div>
---
## Opciones Comunes de Transición ⚙️
Todas las transiciones pueden aceptar un objeto de opciones para una mayor personalización. Aquí están las más comunes:
| Opción | Tipo | Descripción | Valor por Defecto |
| :---------- | :-------- | :-------------------------------------------------------------------------- | :---------------- |
| `duration` | `number` | Duración total de la transición en milisegundos. | `400` |
| `delay` | `number` | Retraso antes de que comience la transición en milisegundos. | `0` |
| `easing` | `function`| Función de *easing* para la animación (ej: `linear`, `cubicOut`). | `cubicOut` |
| `css` | `function`| Función CSS personalizada para generar el estilo de la animación. | (definido por la transición) |
| `tick` | `function`| Función que se ejecuta en cada *frame* de la animación. | (no aplica) |
Las funciones de *easing* son esenciales para que las animaciones se sientan naturales. Svelte exporta varias funciones de *easing* desde `svelte/easing`. Algunas populares son `linear`, `easeIn`, `easeOut`, `easeInOut`, `bounceOut`, `elasticOut`.
```javascript
import { cubicOut } from 'svelte/easing';
// ... dentro de un componente
<p transition:fade={{ duration: 1000, delay: 500, easing: cubicOut }}>
Fade lento con cubicOut.
</p>
Creando Transiciones Personalizadas 🎨
Las transiciones integradas son geniales, pero a menudo necesitarás efectos únicos. Svelte te permite crear tus propias transiciones personalizadas, lo que abre un mundo de posibilidades creativas.
Una transición personalizada es una función que recibe el node del DOM que se va a animar y un objeto params (las opciones que le pasas, como duration, delay, etc.). Esta función debe devolver un objeto que puede contener duration, delay, easing, css y/o tick.
La Función css
La forma más común y sencilla de crear una transición personalizada es devolver una función css. Esta función recibe un parámetro t, que es un valor entre 0 y 1 que representa el progreso de la animación. t=0 al inicio de la animación y t=1 al final.
Ejemplo: Transición de Onda (Wave)
Imagina que quieres que un elemento aparezca con un efecto de onda, como si se expandiera y luego se contrajera un poco antes de asentarse.
Primero, crea un archivo transitions.js (o similar):
// src/transitions.js
import { quintOut } from 'svelte/easing';
export function wave(node, { duration = 800, delay = 0, easing = quintOut } = {}) {
return {
duration,
delay,
easing,
css: t => {
// t es el progreso de la animación (0 a 1)
// Para un efecto de onda, queremos que escale un poco más de 1 y luego vuelva a 1
const scale = Math.sin(t * Math.PI) * 0.2 + 0.8; // Oscila entre 0.8 y 1.0 (o más, ajusta 0.2)
const opacity = t;
return `
opacity: ${opacity};
transform: scale(${scale});
`;
}
};
}
Luego, úsala en tu componente:
<script>
import { wave } from './transitions.js';
let showContent = false;
</script>
<button on:click={() => (showContent = !showContent)}>Toggle Wave</button>
{#if showContent}
<div in:wave out:fade={{ duration: 200 }} class="wave-box">
<h2>¡Hola con Onda!</h2>
<p>Este contenido aparece con una animación personalizada de onda.</p>
</div>
{/if}
<style>
.wave-box {
background-color: #f0f8ff;
border: 1px solid #add8e6;
padding: 20px;
margin-top: 20px;
border-radius: 8px;
text-align: center;
}
</style>
La Función tick
En casos más avanzados, donde necesitas animar propiedades que no son CSS (por ejemplo, el valor de un número o el texto de un elemento), puedes usar la función tick. Esta función se ejecuta en cada frame de la animación y recibe t (progreso) y u (un-progress, 1-t).
Ejemplo: Contador Animado
<script>
import { linear } from 'svelte/easing';
function count(node, { duration = 1000, delay = 0, to = 0 } = {}) {
let from = Number(node.textContent);
return {
duration,
delay,
easing: linear,
tick: t => {
node.textContent = Math.round(from + t * (to - from));
}
};
}
let showCounter = false;
let targetCount = 100;
</script>
<button on:click={() => (showCounter = !showCounter)}>Toggle Counter</button>
{#if showCounter}
<p in:count={{ to: targetCount }}>0</p>
{/if}
Transiciones Locales vs. Globales 🌍
Por defecto, las transiciones son globales. Esto significa que si un elemento se mueve dentro del DOM (por ejemplo, al reordenar una lista), Svelte no animará su posición. La transición solo se aplica cuando el elemento se añade o se elimina del DOM.
Sin embargo, Svelte ofrece la directiva local para las transiciones. Al añadir local a una transición (transition:fade|local), le indicas a Svelte que solo debe aplicar esa transición si el componente padre no ha cambiado. Es útil en ciertos contextos, pero generalmente trabajamos con transiciones globales para la entrada/salida de elementos.
¿Cuándo usar `local`?
Usa `local` cuando tengas un bloque `{#each}` y quieras que las transiciones de entrada/salida de los elementos de la lista se activen solo cuando el elemento *realmente* se añade o quita, y no cuando se reordena la lista. Si los elementos se reordenan, Svelte usa su sistema de *keying* para mover los elementos, y las transiciones de movimiento son un tema aparte (`animate:`).Las Directivas in y out 🚪🚶
Hasta ahora hemos usado transition:nombre. Esta es una abreviatura que aplica la misma animación para la entrada y la salida. Pero, ¿y si quieres un efecto diferente al aparecer y al desaparecer?
Aquí es donde entran in:nombreDeTransicion y out:nombreDeTransicion.
<script>
let showModal = false;
</script>
<button on:click={() => (showModal = !showModal)}>Abrir Modal</button>
{#if showModal}
<div
in:fly={{ y: -200, duration: 500 }}
out:fade={{ duration: 300 }}
class="modal-backdrop"
on:click={() => (showModal = false)}
>
<div class="modal-content" on:click|stopPropagation>
<h3>¡Bienvenido al Modal!</h3>
<p>Este modal vuela al entrar y se desvanece al salir.</p>
<button on:click={() => (showModal = false)}>Cerrar</button>
</div>
</div>
{/if}
<style>
.modal-backdrop {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background-color: rgba(0,0,0,0.6);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background-color: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
text-align: center;
max-width: 500px;
width: 90%;
}
</style>
En este ejemplo, el modal vuela hacia abajo al aparecer y luego se desvanece al desaparecer, creando una experiencia de usuario más rica.
Transiciones de Grupo y Bloques {#each} 🧑🤝🧑
Cuando trabajas con listas de elementos ({#each} bloques), las transiciones se aplican a cada elemento individualmente a medida que se añaden o eliminan de la lista. Esto es extremadamente potente para listas dinámicas.
<script>
let items = ['Manzana', 'Banana', 'Cereza'];
let newItem = '';
function addItem() {
if (newItem) {
items = [...items, newItem];
newItem = '';
}
}
function removeItem(itemToRemove) {
items = items.filter(item => item !== itemToRemove);
}
</script>
<h2>Mi Lista de Frutas Animada</h2>
<input type="text" bind:value={newItem} placeholder="Añadir fruta" />
<button on:click={addItem}>Añadir</button>
<ul>
{#each items as item (item)}
<li transition:slide={{ duration: 300 }}>
{item}
<button on:click={() => removeItem(item)}>X</button>
</li>
{/each}
</ul>
<style>
ul {
list-style: none;
padding: 0;
margin-top: 20px;
}
li {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #e0f2f7;
padding: 10px 15px;
margin-bottom: 5px;
border-radius: 5px;
border: 1px solid #b2ebf2;
}
li button {
background-color: #ef9a9a;
color: white;
border: none;
padding: 5px 10px;
border-radius: 3px;
cursor: pointer;
}
</style>
En este ejemplo, cada elemento de la lista se desliza al aparecer y desaparecer, lo que mejora la usabilidad y el atractivo visual al interactuar con la lista.
Diagrama de Flujo de una Transición 📊
Para entender mejor cuándo se activan las transiciones, aquí hay un diagrama simplificado:
Este diagrama ilustra cómo Svelte decide qué transición aplicar basándose en la presencia o ausencia de un elemento en el DOM.
Mejorando la Experiencia de Usuario con Transiciones Avanzadas 🚀
Crossfading (Transición Cruzada)
¿Qué pasa si quieres reemplazar un elemento por otro con una animación suave, como un crossfade?
Svelte tiene una función crossfade que genera transiciones send y receive para esto. Esto es ideal para animar el movimiento de elementos entre diferentes contenedores o estados.
<script>
import { crossfade } from 'svelte/transition';
import { quintOut } from 'svelte/easing';
let todos = [
{ id: 1, text: 'Aprender Svelte', done: false },
{ id: 2, text: 'Construir una App', done: false },
{ id: 3, text: 'Dominar Transiciones', done: true }
];
const [send, receive] = crossfade({
duration: 600,
easing: quintOut,
fallback: fade
});
function toggleDone(id) {
todos = todos.map(todo =>
todo.id === id ? { ...todo, done: !todo.done } : todo
);
}
</script>
<style>
.list-container {
display: flex;
gap: 20px;
margin-top: 30px;
}
.todo-list, .done-list {
flex: 1;
border: 1px solid #ccc;
padding: 15px;
border-radius: 8px;
min-height: 150px;
}
.todo-item {
background-color: #f9f9f9;
border: 1px solid #eee;
padding: 10px;
margin-bottom: 8px;
border-radius: 5px;
display: flex;
justify-content: space-between;
align-items: center;
}
.done .todo-item {
background-color: #e6ffe6;
border-color: #ccffcc;
text-decoration: line-through;
}
</style>
<h1>Lista de Tareas</h1>
<div class="list-container">
<div class="todo-list">
<h3>Pendientes</h3>
{#each todos.filter(t => !t.done) as todo (todo.id)}
<div
class="todo-item"
transition:send|local={{ key: todo.id }}
transition:receive|local={{ key: todo.id }}
>
{todo.text}
<button on:click={() => toggleDone(todo.id)}>✅</button>
</div>
{/each}
</div>
<div class="done-list">
<h3>Completadas</h3>
{#each todos.filter(t => t.done) as todo (todo.id)}
<div
class="todo-item done"
transition:send|local={{ key: todo.id }}
transition:receive|local={{ key: todo.id }}
>
{todo.text}
<button on:click={() => toggleDone(todo.id)}>↩️</button>
</div>
{/each}
</div>
</div>
En este ejemplo, cuando una tarea se marca como done o viceversa, no solo desaparece de una lista y aparece en otra; en su lugar, se anima su movimiento entre las dos listas gracias a crossfade.
animate: para Movimiento de Elementos 💫
Svelte 3 introdujo la directiva animate: para animar cambios de posición de elementos en listas {#each}. A diferencia de transition, animate se encarga de la animación de movimiento de un elemento cuando su posición cambia en el DOM.
Por ejemplo, si reordenas una lista de elementos, animate: hará que los elementos se muevan suavemente a sus nuevas posiciones en lugar de saltar instantáneamente.
<script>
import { flip } from 'svelte/animate';
let items = ['Uno', 'Dos', 'Tres', 'Cuatro'];
function shuffle() {
items = items.sort(() => Math.random() - 0.5);
}
</script>
<style>
ul {
list-style: none;
padding: 0;
margin-top: 20px;
}
li {
background-color: #ffe0b2;
padding: 10px 15px;
margin-bottom: 5px;
border-radius: 5px;
border: 1px solid #ffcc80;
}
</style>
<h2>Elementos Reordenables</h2>
<button on:click={shuffle}>Reordenar Aleatoriamente</button>
<ul>
{#each items as item (item)}
<li animate:flip={{ duration: 500 }}>{item}</li>
{/each}
</ul>
La función flip (First Last Invert Play) es la animación por defecto que usa Svelte para animate:. Calcula la diferencia de posición entre el estado antes y después del cambio de orden, y luego anima ese movimiento.
Consideraciones de Rendimiento y Accesibilidad 🚦
Aunque las transiciones son poderosas, es importante usarlas con moderación y considerar su impacto:
- Rendimiento: Demasiadas animaciones o animaciones muy complejas pueden afectar el rendimiento, especialmente en dispositivos de gama baja. Optimiza las duraciones y utiliza propiedades CSS que son eficientes para animar (transform, opacity).
- Accesibilidad:
- Preferencias de Movimiento Reducido: Algunas personas prefieren menos movimiento en la interfaz debido a problemas de salud (vértigo, ansiedad). Respeta la preferencia del usuario
prefers-reduced-motiona través de CSS o JavaScript. Svelte facilita esto internamente, pero es buena práctica estar consciente. - Duraciones: Evita animaciones excesivamente largas que puedan frustrar a los usuarios.
- Contexto: Asegúrate de que las animaciones añadan significado y no distraigan o confundan al usuario.
- Preferencias de Movimiento Reducido: Algunas personas prefieren menos movimiento en la interfaz debido a problemas de salud (vértigo, ansiedad). Respeta la preferencia del usuario
Conclusión ✅
Las Svelte Transitions son una de las características más elegantes y potentes que ofrece el framework. Permiten a los desarrolladores crear interfaces de usuario dinámicas y fluidas con un mínimo esfuerzo, mejorando significativamente la experiencia del usuario.
Desde las sencillas transiciones fade y slide hasta las personalizadas con css o tick, y el avanzado crossfade o animate:flip, Svelte te equipa con todo lo necesario para que tus aplicaciones cobren vida. Practica con los ejemplos, experimenta con diferentes easings y duraciones, y no dudes en crear tus propias transiciones para dar un toque único a tus proyectos.
¡Anímate a explorar y animar tus componentes Svelte! ¡El resultado será una aplicación no solo funcional, sino también increíblemente atractiva!
Tutoriales relacionados
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!