https://www.bram.us/wordpress/wp-content/uploads/2024/10/ssstwitter.com_1728373297963.mp4Recording of Paul’s demoDissecting and reworking a very nice demo by Paul Noble.

~

Card Stack DemoPaul Noble created an AMAZING scroll-driven animations demo in which you can drag cards from a card stack. As he describes it:

Card stack using scroll-driven animation w/ snapping. Just a few lines of JS, zero dependencies.

Try it out (in Chrome) right here:

See the Pen
Scroll-driven animated card stack with scroll snap events. by Paul Noble (@paulnoble)
on CodePen.

The logic/math used for the stack is based on this thread by Nate Smith

~

💁‍♂️ Unfamiliar with Scroll-Driven Animations? Don’t worry, I’ve created a free video course “Unleash the Power of Scroll-Driven Animations” which teaches you all there is to know about Scroll-Driven Animations.

Go check it out to become an expert in Scroll-Driven Animations!

~

Dissecting the code On social media I already shared (Twitter, Mastodon) how Paul built it:

Invisible ScrollerThe first clever thing Paul is doing there is using an invisible scroller laid on top of the stack of cards. This scroller gets a ScrollTimeline named --scroll-timeline attached to it.Hoisting the TimelineTo make the .card-stack see the --scroll-timeline, it gets hoisted using timeline-scope on the body. Any child of the body – including .card-stack – can therefore use that --scroll-timeline.Scroll-SnappingTo make the cards always show at the center, CSS scroll-snapping is used.Snap EventsIn his demo, Paul also uses the new scrollsnapchange event to let the markup know which card has snapped. This is propagated through the data-active-index attribute on the main element.Custom animations based on which card has snapped Based on the data-active-index attribute, different animations are attached to the cards: the snapped card gets an active animation – which rotates in 3D around the stack – and the non-snapped cards get an inactive animation – which rotates the card around its base.~

Remixing the demoPaul’s demo is amazing but also hard to read because the Sass code uses quite some some math to generate keyframes for each card. As hinted on social media I was quite sure that the effect can also be done using shared keyframes for each card. To attach the keyframes to a single .card a ViewTimeline on the linked .scroll-item can be used, and using animation-range it’s possible to limit when the animation should run.

Yesterday evening I put my money where my mouth is and took my idea for a spin. The result is not 100% perfect – there are some 3D stacking issue, most likely I need to tweak the animation-ranges a bit more – but the result comes pretty close to the original:

See the Pen
Scroll-driven animated card stack with scroll snap events (Vanilla) by Bramus (@bramus)
on CodePen.

While at it, I also reworked the scrollSnapChange logic to use event.snapTargetInline and by also providing a fallback using IntersectionObserver in browsers with no support for the Snap Events.

~

🔥 Like what you see? Want to stay in the loop? Here's how:

  • Follow @bramus on Twitter
  • Follow @bramus on Mastodon
  • Follow @bramusblog on Twitter
  • Follow bram.us using RSS