Run a Scroll-Driven Animation only once

By admin

Scroll-Driven Animations
ORG

are controlled by scroll: as you scroll up and down, the animation will scrub forwards and back, in direct response. But what if you want a scroll-driven animation to stay on its endframe once it was entirely played? Let this little piece of

JavaScript
PRODUCT

help you out …

~

# The Code

If you’re here for just the code, you can import runOnce from the

@bramus
ORG

/sda-utilities package.

import { runOnce } from ‘

@bramus
ORG

/sda-utilities’; // Run the “fade-in” scroll-driven animation on the `#hero` element only once. window.addEventListener(‘load’, (e) => { const $hero = document.querySelector(‘#hero’); runOnce($hero, ‘fade-in’); });

To see this snippet in action in, go check out the demo.

The source code of the runOnce function itself is available on GitHub. You can check the package details on NPM.

~

# How to use

Call the runOnce function and pass in a reference to an element along with the name of the animation you want to run only once:

document.querySelectorAll(".photo").forEach(($photo) => { runOnce($photo, "animate-in"); });

The passed in animation name – here animate-in – is optional. When not passing in a name, all

Scroll-Driven Animations
ORG

attached to that element will only run once.

☝️ In theory, you can run this code from the moment the elements you are targeting are available in the

DOM
ORG

. Unfortunately there is a bug in

Chrome 115-117
PRODUCT

where

Scroll-Driven Animations
ORG

might trigger rogue

animationend
PRODUCT

events while the timeline is still being calculated. The bug is fixed in

Chrome
ORG

118.0.5993.11, but for earlier versions you need a small workaround. Thankfully the workaround is pretty simple: only attached the event listeners after the window ’s load event has been triggered. window.addEventListener("load", (e) => { document.querySelectorAll(".photo").forEach(($photo) => { runOnce($photo, "animate-in"); }); });

~

# How it works

At its core, the code listens for the

animationend
FAC

event on the passed in element. From that element, the relevant animation is filtered out and then stopped.

$el.addEventListener(‘animationend’, (e) => { const animation = animations.find((a) => a.animationName == e.animationName); if (shouldAnimationBeStopped(animation, animationName)) { animation.commitStyles(); animation.cancel(); } });

To effectively stop the animation, the computed values of the animation’s current styles are written to the element using animation.commitStyles(); before animation.cancel(); ever gets called.

To prevent glitches upon removal, it’s best to set the animation-fill-mode to forwards or both . If you’ve not done this, the function will give you a warning on the

Console
LOC

that glitches might occur in this case.

☝️ The way the animation gets filtered from the element’s list of animations works in all commmon scenarios but will go wrong when you’ve got multiple animations that have the same name attached. As a workaround, use unique animation names for each animation on an element. As per recent

CSS WG Resolution
LAW

, the animation-* events have been updated to also get the actual Animation object passed in, fixing this problem. At the time of writing, however, this is not implemented by any browser. The

Chromium
ORG

bug tracking this adjustment is https://crbug.com/1479139.

~

You can find a demo on CodePen:

See the Pen Run Scroll-Driven Animations only once by

Bramus
PERSON

(

@bramus
ORG

) on CodePen.

To make it very clear when the animation was finished, a lime border is drawn around each subject that has reached that state.

~

# Spread the word

To help spread the contents of this post, feel free to retweet its announcement tweet:

New blogpost: “

Run a Scroll-Driven Animation
WORK_OF_ART

only once” A small piece of

JavaScript
PRODUCT

to run a scroll-driven animation only once. 🔗 https://t.co/kzsxrTIjQn 🏷️

#css #js #
MONEY


ScrollDrivenAnimations —
WORK_OF_ART


Bram.us
PERSON

(by

@bramus
ORG

) (

@bramusblog) October 5, 2023
DATE

~



Play Once
WORK_OF_ART

” icon from the Phosphor Light Vol.4 icon pack