texto para paginas ejemplos efectos con animaciones animacion javascript css animation tabs css-animations

javascript - para - Pausa/reanuda las animaciones CSS al cambiar de pestaña



efectos de animacion jquery (3)

Tengo un montón de animaciones CSS de larga duración en una página. Quiero hacer una pausa cuando un usuario cambia a otra pestaña y reanudarlas cuando el usuario vuelve a la pestaña original. En aras de la simplicidad, no pretendo una solución para varios navegadores en este momento; Hacer que funcione en Chrome debería ser suficiente.

document.addEventListener("visibilitychange", function() { if (document.hidden) { document.querySelector("#test").classList.add("paused"); } else { document.querySelector("#test").classList.remove("paused"); } });

div#test { width: 50px; height: 50px; background-color: red; position: absolute; left: 10vw; animation-name: move; animation-duration: 5s; animation-fill-mode: forwards; animation-timing-function: linear; } @keyframes move { to { left: 90vw } } .paused { animation-play-state: paused !important; -webkit-animation-play-state: paused !important; -moz-animation-play-state: paused !important; }

<div id="test"></div>

El código de arriba mueve un rectángulo rojo horizontalmente. El rectángulo tarda 5 segundos en completar la animación.

El problema: después de que comience la animación, cambie a otra pestaña del navegador; después de un período de tiempo (más de 5 segundos), vuelva a la primera pestaña.

Resultado esperado: el rectángulo continúa su recorrido desde el punto donde lo dejó.

Resultado real: la mayoría de las veces el rectángulo aparece en su destino final y se detiene. A veces funciona como se espera. El video muestra el problema.

Jugué con diferentes valores para el animation-fill-mode animation-timing-function , pero el resultado fue siempre el mismo. Como señaló rv7, compartir los ejemplos en CodePen, JSFiddle, JSBin y stackoverflow JS afecta a los resultados, por lo que es mejor probar directamente contra una página estática en un servidor HTTP local (o mediante los enlaces a continuación).

Para mayor comodidad, he desplegado el código anterior a Heroku . La aplicación es un servidor HTTP estático de nodejs, que se ejecuta en una suscripción gratuita, por lo que la primera carga de la página puede demorar hasta 5 minutos. Resultados de pruebas en esta página:

FAIL Chrome 64.0.3282.167 (versión oficial) (64 bits) Linux Debian Stretch (PC)
FAIL Chrome 70.0.3538.67 (versión oficial) (64 bits) Windows 10 (PC)
FAIL Chrome 70.0.3538.77 (versión oficial) (32 bits) Windows 7 (PC)
FAIL Chrome 70.0.3538.77 (versión oficial) (64 bits) OSX 10.13.5 (Mac mini)
FAIL FF Quantum 60.2.2esr (64 bits) Linux Debian Stretch (PC)
OK Safari 11.1.1 (13605.2.8) (Mac mini)

La API de visibilidad de la página se puede reemplazar con eventos de focus ventana y blur como este:

window.addEventListener("focus", function() { document.querySelector("#test").classList.remove("paused"); }); window.addEventListener("blur", function() { document.querySelector("#test").classList.add("paused"); });

Sin embargo, este reemplazo no es equivalente. Si una página contiene IFRAME, la interacción con su contenido activará los eventos de focus y blur en la ventana principal. La ejecución de cualquier código de cambio de pestaña en este caso no es correcta. Esta podría ser una opción en algunos casos, así que implementé una página para probar here . Los resultados son ligeramente mejores:

FAIL Chrome 64.0.3282.167 (versión oficial) (64 bits) Linux Debian Stretch (PC)
FAIL Chrome 70.0.3538.67 (versión oficial) (64 bits) Windows 10 (PC)
FAIL Chrome 70.0.3538.77 (versión oficial) (32 bits) Windows 7 (PC)
FAIL Chrome 70.0.3538.77 (versión oficial) (64 bits) OSX 10.13.5 (Mac mini)
OK FF Quantum 60.2.2esr (64 bits) Linux Debian Stretch (PC)
OK Safari 11.1.1 (13605.2.8) (Mac mini)
Esta versión falla con más frecuencia en Chrome de 64 bits que en Chrome de 32 bits. En Chrome de 32 bits obtuve solo 1 error después de ~ 20 intentos exitosos. Esto podría estar relacionado con el hecho de que Chrome de 32 bits está instalado en hardware anterior.

La pregunta: ¿hay una manera de pausar / reanudar de manera confiable las animaciones de CSS al cambiar de pestaña?


¡Puede ir con los eventos de focus y blur lugar del evento con visibilitychange debido a un mejor soporte de navegador para el primero!

let box = document.querySelector(''#test''); window.addEventListener(''focus'', function() { box.style.animationPlayState = ''paused''; }); window.addEventListener(''blur'', function() { box.style.animationPlayState = ''running''; });

Alternativamente, también puedes hacer esto usando clases de CSS:

.paused { animation-play-state: paused !important; -webkit-animation-play-state: paused !important; -moz-animation-play-state: paused !important; }

let box = document.querySelector(''#test''); window.addEventListener(''focus'', function() { box.classList.remove(''paused''); }); window.addEventListener(''blur'', function() { box.classList.add(''paused''); });

Las dos formas anteriores no funcionan en el iframe de CodePen, JSFiddle, JSBin, etc; Una posible razón se proporciona al final del post. Pero, aquí hay un enlace de video que muestra cómo funciona el código en el modo de depuración de CodePen .

Ejemplo vivo

Confirmado en :

  1. Google Chrome v70.0.3538.67 (versión oficial) (32 bits)

  2. Firefox Quantum v62.0.3 (32 bits)

  3. Internet Explorer v11 +

Posible razón de por qué el código no funciona dentro de iframe :

Cuando intenté acceder a la root window (también conocido como objeto parent , tenga en cuenta que no es la iframe window ), se registra el siguiente error en la consola:

Y esto significa que no puedo acceder a la root window de CodePen y otros. Por lo tanto, si no puedo acceder a él, no puedo agregarle ningún detector de eventos.


No es necesario usar ninguna clase o alternarlas para obtener el resultado esperado. Aquí, descargue este archivo html e intente al final, veamos si esto funciona.

Debe establecer el animation-play-state la animation-play-state mientras escribe CSS para que el div de test detenga.

Una vez que se cargue la ventana, establezca el animation-play-state la animation-play-state en running luego configúrelos nuevamente de acuerdo con el evento de blur y focus .

También noté que usar el prefijo del navegador (-webkit-animation-play-state) me ayudó a obtener el resultado esperado, así que asegúrate de usarlos. He probado en Firefox y Chrome, funciona bien para mí.

Nota: Esto podría no funcionar en este fragmento de código aquí (ya que el fragmento no se encuentra en la ventana principal de esta pestaña actual). Descargue el vínculo principal proporcionado anteriormente y verifique su final.

window.onload = function() { // not mentioning the state at all does not provide the expected result, so you need to set // the state to paused and set it to running on window load document.getElementById(''test'').style.webkitAnimationPlayState = "running"; document.getElementById(''test'').style.animationPlayState = ''running''; } window.onblur = function() { document.title = ''paused now''; document.getElementById(''test'').style.webkitAnimationPlayState = "paused"; document.getElementById(''test'').style.animationPlayState = ''paused''; document.getElementById(''test'').style.background = ''pink''; // for testing } window.onfocus = function() { document.title = ''running now''; document.getElementById(''test'').style.webkitAnimationPlayState = "running"; document.getElementById(''test'').style.animationPlayState = ''running''; document.getElementById(''test'').style.background = ''red''; // for testing }

div#test { width: 50px; height: 50px; background-color: red; position: absolute; left: 10vw; animation-name: move; animation-duration: 5s; animation-fill-mode: forwards; animation-timing-function: linear; /* add the state here and set it to running on window load */ -webkit-animation-play-state: paused; animation-play-state: paused; } @keyframes move { to { left: 90vw } }

<div id="test"></div>


Para mí tu ejemplo funciona la mayor parte del tiempo.

Sin embargo, usaría porcentajes y también agregaría un punto de inicio en los fotogramas clave:

@keyframes move { 0% { left: 0px; } 100% { left: 500px } }

También la detección de pestañas inactivas no se dispara siempre. Una ventana inactiva parece funcionar mejor: (con jQuery)

$(window).on("blur focus", function(e) { var prevType = $(this).data("prevType"); if (prevType != e.type) { var element = document.getElementById("test"); switch (e.type) { case "blur": element.style["animation-play-state"] = "paused"; break; case "focus": element.style["animation-play-state"] = "running"; break; } } $(this).data("prevType", e.type); })