0

I'm using Web Animations API to animate DOM elements. I want to display animation progress after 1 second.

This is what I've tried.

const animation = div.animate({
  opacity: 0
}, {
  duration: 2000
});
setTimeout(() => console.log(animation.effect.getComputedTiming().progress), 1000);

I expect 0.5 to be displayed because setTimeout function is invoked when the animation is halfway through. The problem is that 0.0083 is printed

Ezys
  • 3
  • 1
  • [I get 0.49998...](https://jsfiddle.net/o7t08fus/) – Kaiido Jan 30 '22 at 12:43
  • I'm confused. I've ran it on my old Macbook and it printed 0.49. Then I tried to run on Windows using Chrome and it keeps printing 0.005 – Ezys Jan 30 '22 at 13:02
  • Weird indeed, I'm on a mac so for me it works fine, no Windows machine at hand right now to test, but it should just work. – Kaiido Jan 30 '22 at 14:27
  • Ah I could reproduce on Chrome for Android, this seems to be a bug with how they mark the document as animated. I was able to workaround it in my Android by forcing a requestAnimationFrame callback. https://jsfiddle.net/sepuonrm/ Can you confirm it works on your system too? I'll open an issue tomorrow (it's late here) – Kaiido Jan 30 '22 at 14:54
  • Prints a value from `0` to `0.00833299999999998`. You can test it here: https://www.browserling.com/online-browser . Still, would recommed avoiding the Animations API until its stable – savageGoat Jan 30 '22 at 15:17
  • 1
    It is working better than before, but I get some inconsistent results like 0.29 0.17 0.2 0.49 – Ezys Jan 30 '22 at 15:21

1 Answers1

1

Animations generated using animate() (or CSS animations/transitions for that matter) do not start immediately.

Rather, browsers perform necessary set up work first, such as splitting the content into suitable layers, rendering those layers, passing the layers and animation information over to the compositor thread/process and then starting the animation (and resolving the ready promise from the Animation object that animate() returns).

Because this setup cost is often non-zero (especially on lower-end devices), if browsers did not do this the animation would jump when it starts because by the time the browser finally got to display the animation the current time of the animation would already be past 0ms. e.g. if the browser took 100ms to set up the animation, the first half a dozen frames would be dropped and the animation would jump.

(For what it's worth, one of the motivations behind will-change was to allow authors to pay this setup cost upfront so the animation can start more quickly.)

All browsers perform this optimization but the precise timing varies from browser to browser and the setup cost will vary between devices and platforms. The Animation.ready promise is provided so you can wait until the animation has actually started regardless of the browser/platform/device.

You can force the animation to start immediately, however, by setting the startTime directly. For example,

const animation = elem.animate(...);
animation.startTime = document.timeline.currentTime;

This, however, may cause the first few frames of your animation to be dropped, particularly on lower-end devices.

brianskold
  • 809
  • 5
  • 10