jQuery / .animate() — Crear efectos personalizados
.animate() cambia propiedades CSS actuales hasta sus objetivos con el tiempo. .animate({ left: 100, width: 160, opacity: 0.4 }) modifica posición, ancho y opacidad juntos. Duración y easing controlan el recorrido; la finalización se llama por elemento.
Propiedades y duración
El primer argumento .animate() contiene objetivos. left y width numéricos son píxeles aquí; opacity no tiene unidad y va de cero a uno. Un objeto cambia simultáneamente; llamadas separadas entran normalmente en la cola.
left necesita posición distinta de static. relative desplaza desde el origen, no a x=100 del documento. width mide contenido; content-box simple evita condiciones extra de borde y padding.
duration son milisegundos, 400 por defecto. Easing cambia velocidad: swing y linear llegan a los mismos objetivos. No suponga interpolación de cualquier color o transform por jQuery básico; revise propiedades numéricas admitidas.
Ejemplo completo con dos elementos
Guarde UTF-8 animate-demo.html y abra. Internet carga la versión completa oficial 4.0.0. Animación temporizada necesita effects, no Slim. No necesita servidor ni paquetes. Intermedios, objetivos, parada y repetición se comprobaron en Edge para Windows con 3.7.1 y 4.0.0.
Las cajas comparten objetivos. Start restaura valores iniciales. Reset conserva duración/easing y restaura cajas y contadores. Durante ejecución se bloquea otro inicio.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Animate CSS properties and observe completion</title>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<style>
body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 20px; }
label { display: block; margin: 8px 0; }
select, button { font: inherit; margin: 4px; }
#stage { background: #eef4f4; padding: 10px; overflow-x: auto; }
.box { position: relative; left: 0; width: 80px; height: 45px; margin: 12px 0; background: teal; color: white; box-sizing: content-box; }
pre { white-space: pre-wrap; overflow-wrap: anywhere; }
</style>
</head>
<body>
<label>Duration <select id="duration"><option value="600">600ms</option><option value="1200">1200ms</option><option value="0">0ms</option></select></label>
<label>Easing <select id="easing"><option value="swing">swing</option><option value="linear">linear</option></select></label>
<button type="button" id="start">Start</button>
<button type="button" id="stop">Stop here</button>
<button type="button" id="reset">Reset</button>
<div id="stage"><div class="box" id="alpha">Alpha</div><div class="box" id="beta">Beta</div></div>
<pre id="result" aria-live="polite"></pre>
<script>
jQuery(function ($) {
const $boxes = $("#stage > .box");
let generation = 0, busy = false, state = "ready", completed = 0, batches = 0;
function report() {
const values = $boxes.map(function () {
const $box = $(this);
return this.id + ": left=" + Math.round(parseFloat($box.css("left"))) + "; width=" + Math.round($box.width()) + "; opacity=" + Number(parseFloat($box.css("opacity")).toFixed(2));
}).get();
$("#result").text(["state=" + state, "completed=" + completed + "; batches=" + batches, ...values].join("\n"));
}
function reset() {
generation++; $boxes.stop(true, false).css({ left: 0, width: 80, opacity: 1 });
busy = false; state = "ready"; completed = batches = 0;
$("#start").prop("disabled", false); report();
}
$("#start").on("click", function () {
if (busy) return;
reset(); busy = true; state = "running"; $(this).prop("disabled", true);
const run = generation;
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
const duration = reduce ? 0 : Number($("#duration").val());
$boxes.animate({ left: 100, width: 160, opacity: 0.4 }, {
duration: duration, easing: $("#easing").val(),
complete: function () { if (run === generation) { completed++; report(); } }
});
$boxes.promise("fx").done(function () {
if (run !== generation) return;
batches++; busy = false; state = "done";
$("#start").prop("disabled", false); report();
});
report();
});
$("#stop").on("click", function () {
if (!busy) return;
generation++; $boxes.stop(true, false);
busy = false; state = "stopped"; $("#start").prop("disabled", false); report();
});
$("#reset").on("click", reset);
reset();
});
</script>
</body>
</html>
Inicio: ancho 80, left relativo cero y opacidad uno. Redondear pantalla no limita el cálculo a enteros.
state=ready
completed=0; batches=0
alpha: left=0; width=80; opacity=1
beta: left=0; width=80; opacity=1
- Start con 600ms y swing: tres propiedades cambian juntas.
- Final: state=done, completed=2; batches=1 ; ambas left=100; width=160; opacity=0.4.
- Reset, cambie solo easing a linear y compare. Los objetivos coinciden.
- Con 1200ms, Stop here conserva intermedios en state=stopped, sin done posterior.
- Reset y repita. 0ms alcanza objetivos y contadores inmediatamente.
- Movimiento reducido también termina inmediatamente aunque elija 1200ms.
Final individual y colectivo
complete se llama dos veces y this es el nodo correspondiente. Un callback no es el final colectivo. .animate() no bloquea JavaScript hasta terminar.
.promise("fx") observa trabajo del conjunto. Aquí incrementa batches una vez y habilita Start. Tareas adicionales de la cola estándar pueden ampliar la espera.
Cola vacía no demuestra final natural. .stop(true, false) puede vaciar a mitad y resolver la promesa fx. Stop y Reset cambian generation primero para que callbacks antiguos no sustituyan cancelación por done.
Llamadas repetidas suelen acumular efectos; deshabilitar y busy lo evitan. Redirigir desde la posición actual necesita otra política explícita.
Parada, restauración y disposición
jumpToEnd=false conserva valores actuales. Reset establece las tres propiedades; intermedios antiguos cambiarían la comparación.
prefers-reduced-motion reduce usa cero en esta ejecución con mismo objetivo y final, sin cambiar configuración global.
Posición y ancho afectan alrededor y solapamientos: revise pantalla estrecha, zoom, texto largo y contenedores desplazables. Opacidad cero no implica display:none ni ocultación accesible.
Evite que transiciones CSS o plugins controlen las mismas propiedades a la vez. Defina responsabilidad de elementos, propiedades y colas, y limite selectores y eventos a la función.




