Animaciones CSS tips y trucos
Corriendo una animación de nuevo
La especificación de CSS Animations no ofrece una forma de ejecutar una animación nuevamente. No hay un método mágico de resetAnimation()
en los elementos, y tu no puedes solo configurar el elemento animation-play-state
para "correr"
de nuevo. En su lugar debes usar trucos inteligentes para que una animación detenida se reproduzca.
Aquí te mostramos una forma de hacerlo que sentimos es lo suficientemente estable y confiable para sugerirte
Contenido HTML
Primero, definamos el HTML para un <div>
que deseamos animar y un botón que ejecurara (o repetira) la animación.
<div class="box"></div>
<div class="runButton">Click me to run the animation</div>
Contenido CSS
Ahora definiremos la animación en si usando CSS. Algún CSS que no es importante (el estilo del botón "Run" en sí) no se muestran aquí, por brevedad.
@keyframes colorchange {
0% {
background: yellow;
}
100% {
background: blue;
}
}
.box {
width: 100px;
height: 100px;
border: 1px solid black;
}
.changing {
animation: colorchange 2s;
}
Aquí hay dos clases. La clase "box"
es un descripción básica de la apariencia de la caja, sin ninguna información de la animación incluida. Los detalles de la animación son incluidos en la clase "changing"
class, que dice que @keyframes
llamado "colorchange"
debe usarse en el transcurso de dos segundo para animar la caja.
Note que debido a esto, la caja no comienza con ningún efecto de animación en su lugar, por lo que no se animará
Contenido JavaScript
Ahora veremos el JavaScript que jace el trabajo. La escencia de la técnica esta en la función play()
, que se llama cuando el usuario hace clic en el botón "Run".
function play() {
document.querySelector(".box").className = "box";
window.requestAnimationFrame(function (time) {
window.requestAnimationFrame(function (time) {
document.querySelector(".box").className = "box changing";
});
});
}
Esto se ve raro, ¿cierto? Esto se debe a que la única forma de volver a reproducir una animación es eleminar el efecto de animación, dejar que el documento vuelva a calcular los estilos para que sepa que lo ha hecho y luego volver a agregar el efecto de animación al elemento. Para que eso suceda, tenemos que ser creativos.
Esto es lo que sucede cuando la función play()
es llamada:
- La lista de clases CSS de caja se restablece a
"box"
. Esto tiene el efecto de remover cualquier otra clase recurrente aplicada a la caja, incluida la clase"changing"
que controla la animación. En otras palabras eliminaremos el efecto de animación de la caja. Sin embargo, los cambios en la lista de clases no tienen efecto hasta que se recalcula completamente el estilo y se ha producido una actualización para reflejar el cambio. - Para estar seguros que los estilos son recalculados, nosotros usamos
window.requestAnimationFrame()
, especifinado un callback. Nuestro callback se ejecuta justo antes del 'repaint' del documento. El problema para nosotros es que debido a que es antes del repaint, ¡El recalculo del estilo aún no ha suciedo! Por lo tanto... - Nuestro callback habilmente llama a
requestAnimationFrame()
¡por segunda vez!. En este momento el callback se compila antes del siguiente repaint, después de que se haya producido el recalculo del estilo. El callback añade la clase"changing"
de nuevo en la caja, para que el repaint inicie la animación una vez más.
Por supuesto, también necesitamos agregar un controlador de eventos a nuestro botón "Run" para que en verdad haga algo
document.querySelector(".runButton").addEventListener("click", play, false);
Resultado
Detener la animación
Simplemente removemos animation-name
aplicado al elemento que hace que eso salte o corte a su siguiente estado.Si, en cambio, desea que la animación se complete y luego se detenga, debe probar un enfoque diferente. Los principales trucos son:
- Haga que su animación sea lo más autónoma posible. Esto significa que no se debe confiar en
animation-direction: alternate
. En su lugar, debe escribir explícitamente una animación de fotogramas clave que pase por la animación completa en una repetición hacia adelante. - Use JavaScript y borre la animación que se esta utilizando cuando se activa el evento
animationiteration
.
El siguiente demo muestra como puedes lograr las técnicas JavaScript mencionandas anteriormente:
.slidein {
animation-duration: 5s;
animation-name: slidein;
animation-iteration-count: infinite;
}
.stopped {
animation-name: none;
}
@keyframes slidein {
0% {
margin-left: 0%;
}
50% {
margin-left: 50%;
}
100% {
margin-left: 0%;
}
}
<h1 id="watchme">Click me to stop</h1>
let watchme = document.getElementById("watchme");
watchme.className = "slidein";
const listener = (e) => {
watchme.className = "slidein stopped";
};
watchme.addEventListener("click", () =>
watchme.addEventListener("animationiteration", listener, false),
);