Tuve que animar la rotación usando vanila JS y encontré el problema con Firefox. setInterval() para animar cada paso de la animación y luego clearInteval() para detener la animación. En este ejemplo, animé la rotación de un elemento. Funciona bien en Chrome, pero no termina la animación en Firefox, como si Firefox tardara más en procesar cada paso. Creé un ejemplo, demostrando este comportamiento.
const circle = document.getElementById('circle') const angle = document.getElementById('angle') const degToMove = 90 //rotate 90 degrees const animStepLength = 10 // 10ms is one animation step const animLength = 300 //whole animation length -> 30 animation steps -> 3deg rotation per step const rotateCircle = () => { rotInterval = setInterval(()=>{ //what rotation value currently is let currentVal = circle.style.transform.match(/[-+]?\d+/); //add 3 deg rotation per step to it circle.style.transform = `rotate(${+currentVal[0] + (degToMove*animStepLength) / animLength}deg)` //text output angle.innerHTML = `${+currentVal[0] + (degToMove*animStepLength) / animLength} deg` }, animStepLength) setTimeout(() => { //after all steps are done clear the interval clearInterval(rotInterval) }, animLength); } circle.addEventListener('click', rotateCircle) body{ display: flex; align-items: center; justify-content: center; margin: 0; height: 100vh; font-family: sans-serif; } #circle{ border-radius: 50%; background-color: skyblue; width: 100px; height: 100px; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; } <div id="circle" style='transform: rotate(0deg)'> <span> Click to rotate </span> <span id="angle">0 deg</span> </div>También disponible como jsfiddle
Mientras que Chrome rota a 90 -> 180 -> 270 -> 360... Firefox va a 57 -> 114 -> 171 -> 228 ->... en este ejemplo en particular. Bueno, esto es básicamente un aumento de +1 rad, pero tiene que ver con los valores seleccionados para animLength y animStepLength . Si los selecciono de manera diferente, Firefox muestra valores diferentes.
La animación CSS simple funcionaría aquí, pero hay razones para que use JS aquí.
Nunca puede garantizar que se llamará a un controlador setTimeout o setInterval cuando se lo solicite. Siempre debe comparar el tiempo actual con el tiempo inicial para determinar qué tipo de progreso debe mostrar su animación, generalmente determinando qué porcentaje de la animación ha transcurrido. Busque la variable de elapsedPercentage en el siguiente ejemplo.
El uso setInterval se considera una mala práctica por ese motivo. La forma sugerida de animar es usar requestAnimationFrame anidado;
La secuencia de comandos a continuación puede usar muchas mejoras, pero le muestra cómo actualizar correctamente su animación en función de cuánto tiempo ha pasado desde que comenzó la animación.
const circle = document.getElementById('circle'); const angle = document.getElementById('angle'); const degToMove = 90; //rotate 90 degrees let rotationStartTime = null; let targetRotation = 0; let rotationStart = 0 let animationTime = 3000; function startRotating() { rotationStartTime = new Date().getTime(); rotationStart = parseInt(circle.style.transform.match(/[-+]?\d+/)[0]); targetRotation += degToMove; rotateCircle(); } function rotateCircle() { const currentVal = parseInt(circle.style.transform.match(/[-+]?\d+/)[0]); const currentTime = new Date().getTime(); const elapsedPercentage = (currentTime - rotationStartTime) / animationTime; let newVal = Math.min(targetRotation, Math.round(rotationStart + (elapsedPercentage * degToMove))); circle.style.transform = `rotate(${newVal}deg)`; //text output angle.innerHTML = `${newVal} deg`; if (newVal < targetRotation) { window.requestAnimationFrame(rotateCircle); } } circle.addEventListener('click', startRotating) body{ display: flex; align-items: center; justify-content: center; margin: 0; height: 100vh; font-family: sans-serif; } #circle{ border-radius: 50%; background-color: skyblue; width: 100px; height: 100px; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; } <div id="circle" style='transform: rotate(0deg)'> <span> Click to rotate </span> <span id="angle">0 deg</span> </div>