1. ¿Qué son las Animaciones en JavaScript?
Las animaciones en JavaScript permiten crear movimiento, transiciones y efectos visuales modificando propiedades CSS o elementos del DOM en el tiempo.
Analogía: El FlipBook
Imagina un flipbook (librito de dibujos animados): cada página muestra el objeto en una posición ligeramente diferente. Al pasar las páginas rápidamente, se crea la ilusión de movimiento. Las animaciones en JavaScript funcionan igual: cambiamos propiedades repetidamente para crear esa ilusión.
2. Métodos para Animar en JavaScript
Comparación de Técnicas
| Técnica | Ventajas | Desventajas | Uso Ideal |
|---|---|---|---|
setInterval |
Simple, predecible | No sincronizado con refresco, consume más recursos | Animaciones simples, relojes |
setTimeout recursivo |
Más control que setInterval | Código más complejo | Animaciones con lógica compleja |
requestAnimationFrame |
Óptimo para rendimiento, sincronizado a 60fps | Ligeramente más complejo | Animaciones suaves y profesionales |
| CSS Transitions/Animations | Máximo rendimiento (GPU) | Menos control dinámico | Animaciones predefinidas simples |
3. Animación con setInterval
Ya vimos setInterval en el módulo de temporizadores. Es la forma más básica de crear
animaciones.
Ejemplo: Movimiento Horizontal
let posicion = 0;
const caja = document.getElementById('caja');
const animacion = setInterval(() => {
posicion += 2;
caja.style.left = posicion + 'px';
if (posicion >= 400) {
clearInterval(animacion);
}
}, 16); // ~60fps (1000ms / 60 ≈ 16ms)
⚠️ Problemas de setInterval para Animaciones
- No sincronizado: No está sincronizado con el refresco de pantalla (60Hz)
- Consume recursos: Sigue ejecutándose aunque la pestaña esté inactiva
- Puede saltar frames: Si el navegador está ocupado, puede dar tirones
4. requestAnimationFrame: La Forma Profesional
requestAnimationFrame() es el método moderno y óptimo para crear animaciones suaves.
Le dice al navegador: "ejecuta esta función justo antes del siguiente repintado de pantalla".
Ventajas de requestAnimationFrame
- ✅ Sincronizado a 60fps: Aprovecha el refresco nativo de la pantalla
- ✅ Ahorro de energía: Se pausa automáticamente en pestañas inactivas
- ✅ Suavidad: El navegador optimiza el timing para animaciones fluidas
- ✅ Rendimiento: El navegador agrupa repintados para eficiencia
Sintaxis Básica
function animar() {
// Tu lógica de animación aquí
// Llamada recursiva para continuar
requestAnimationFrame(animar);
}
// Iniciar la animación
requestAnimationFrame(animar);
Ejemplo: Movimiento con requestAnimationFrame
let posicion = 0;
let animacionId = null;
const caja = document.getElementById('caja');
function animar() {
posicion += 2;
caja.style.left = posicion + 'px';
if (posicion < 400) {
animacionId = requestAnimationFrame(animar);
}
}
// Iniciar
animacionId = requestAnimationFrame(animar);
// Detener (cuando sea necesario)
cancelAnimationFrame(animacionId);
5. Control de Velocidad con Delta Time
Para animaciones independientes de la velocidad de refresco, usamos delta time (tiempo transcurrido entre frames).
let ultimoTiempo = 0;
let posicion = 0;
function animar(tiempoActual) {
// Calcular tiempo transcurrido desde el último frame (en segundos)
const deltaTime = (tiempoActual - ultimoTiempo) / 1000;
ultimoTiempo = tiempoActual;
// Velocidad en píxeles por segundo
const velocidad = 100; // 100px/s
posicion += velocidad * deltaTime;
caja.style.left = posicion + 'px';
if (posicion < 400) {
requestAnimationFrame(animar);
}
}
requestAnimationFrame(animar);
Ejemplo Interactivo: Velocidad Constante
Esta animación mantiene velocidad constante independientemente de los FPS
6. Ejemplo Avanzado: Animación Compleja
Bola Rebotando
let x = 0, y = 0;
let velocidadX = 3;
let velocidadY = 2;
const bola = document.getElementById('bola');
const contenedor = document.getElementById('canvas_rebotar');
function rebotar() {
// Actualizar posición
x += velocidadX;
y += velocidadY;
// Rebotar en los bordes
if (x <= 0 || x >= contenedor.offsetWidth - 30) {
velocidadX = -velocidadX;
}
if (y <= 0 || y >= contenedor.offsetHeight - 30) {
velocidadY = -velocidadY;
}
// Aplicar posición
bola.style.left = x + 'px';
bola.style.top = y + 'px';
requestAnimationFrame(rebotar);
}
requestAnimationFrame(rebotar);
7. Casos de Uso Reales
Scroll Suave
function scrollSuave(destino, duracion) {
const inicio = window.scrollY;
const distancia = destino - inicio;
const tiempoInicio = performance.now();
function paso(tiempoActual) {
const transcurrido = tiempoActual - tiempoInicio;
const progreso = Math.min(transcurrido / duracion, 1);
// Función de easing (suavizado)
const easing = progreso * (2 - progreso); // easeOutQuad
window.scrollTo(0, inicio + distancia * easing);
if (progreso < 1) {
requestAnimationFrame(paso);
}
}
requestAnimationFrame(paso);
}
// Uso: scrollSuave(1000, 500); // Scroll a Y=1000 en 500ms
Contador Animado
function contadorAnimado(elemento, valorFinal, duracion) {
const valorInicial = 0;
const tiempoInicio = performance.now();
function actualizar(tiempoActual) {
const transcurrido = tiempoActual - tiempoInicio;
const progreso = Math.min(transcurrido / duracion, 1);
const valorActual = Math.floor(valorInicial + (valorFinal - valorInicial) * progreso);
elemento.textContent = valorActual;
if (progreso < 1) {
requestAnimationFrame(actualizar);
}
}
requestAnimationFrame(actualizar);
}
8. Buenas Prácticas
✅ Recomendaciones
- Usa
requestAnimationFramepara animaciones visuales - Siempre guarda el ID para poder cancelar la animación
- Usa delta time para animaciones independientes de FPS
- Prefiere transformar propiedades CSS (transform, opacity) sobre position
- Usa
will-changeen CSS para animaciones complejas
❌ Evitar
- Animar con setInterval cuando necesitas suavidad
- Modificar el layout (width, height, position) en loops rápidos
- Olvidar cancelar animaciones que ya no necesitas
- Animar demasiados elementos simultáneamente sin optimizar