scroll-timeline icon indicating copy to clipboard operation
scroll-timeline copied to clipboard

animationstart hook not effective if lazy loaded

Open calinoracation opened this issue 1 year ago • 12 comments

We are asynchronously loading, so the start event has already happened when the polyfill loads in Safari.

I tried various workarounds like waiting for the polyfill to load and switching from play state paused to running.. Perhaps completely not applying until then is an option, but that's tricky for authors.

My current workaround is to apply a data attribute to each element and once loaded query them all and call play on the animations. That does seem to work.

calinoracation avatar Apr 14 '24 17:04 calinoracation

Turns out this is also a problem when we fetch remote stylesheets. The stylesheets themselves are already loaded, but the animationstart event we use to hook into it has already fired after we parse the stylesheets from fetch.

calinoracation avatar Apr 16 '24 21:04 calinoracation

We can use document.getAnimations() and search for all running animations that are an instanceof CSSAnimation and upgrade them. This should handle animations which were already in progress when the polyfill sets up the animationstart listener.

flackr avatar Apr 16 '24 22:04 flackr

I tested this out and that works except for the condition of them running. Most of them have a default duration of 1ms for it to work in Safari so the play-state was not set to running. Otherwise this works like a charm!

calinoracation avatar Apr 17 '24 18:04 calinoracation

Maybe we could temporarily change the fill mode to forwards or both before calling getAnimations() to ensure that even finished animations are still in effect. We could change it back immediately after calling getAnimations to ensure that the change is never visually seen.

flackr avatar Apr 17 '24 19:04 flackr

An alternate option would be to have a very small snippet that is run synchronously which simply collects a list of started animations and then passes them in to be set up by the polyfill after its loaded.

flackr avatar Apr 17 '24 19:04 flackr

The syncronous snippet might be hard, we can't collect it immediately if say a framework like React mounts or re-renders and that triggers an animation after the snippet but before the polyfill is loaded (or remote stylesheets fetched and parsed). The forwards / both sounds promising. Would that be more effective over calling .play() on the animations when the polyfill initializes?

calinoracation avatar Apr 17 '24 19:04 calinoracation

Would that be more effective over calling .play() on the animations when the polyfill initializes?

Yes! This should avoid any visible side effects. Finished animations will remain finished whereas calling play restarts them.

flackr avatar Apr 17 '24 19:04 flackr

we can't collect it immediately if say a framework like React mounts or re-renders and that triggers an animation after the snippet but before the polyfill is loaded

This wouldn't be a problem, you'd simply keep a list of animations to check later to see if they should be scroll driven, e.g.

let startedAnimations = new Set();
window.addEventListener('animationstart', (evt) => {
  evt.target.getAnimations().filter(anim => anim.animationName === evt.animationName).forEach(anim => {
    startAnimations.add(anim);
  });
});

Then after the polyfill loads you'd process each of startedAnimations as if they had an animationstart event, i.e. calling the code here: https://github.com/flackr/scroll-timeline/blob/master/src/scroll-timeline-css.js#L174

flackr avatar Apr 17 '24 19:04 flackr

Let me give that a shot!

calinoracation avatar Apr 17 '24 19:04 calinoracation

It did seem to work, actually. Was also running into another issue where the syntax parser had invalid syntax so stopped processing all animations. That's probably correct, but challenging in a production scenario.

~@flackr That's not working so well for us either. I guess since we put the 1ms duration for Firefox it's not firing animationstart even instrumented early. I've tried a few other things but nothing is sticking so far.~

calinoracation avatar Apr 24 '24 00:04 calinoracation