Scroll Sticky Stack — Free GSAP ScrollTrigger Stacking Cards
Scroll Sticky Stack · Scroll · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Scroll Sticky Stack — Cards That Recede as the Next Slides Over

The scroll sticky stack is the popular effect where full-height cards pin one after another and each shrinks and darkens as the following card slides up to cover it, building a tidy deck instead of scrolling away — the storytelling layout from modern product pages. This snippet combines CSS position: sticky with GSAP ScrollTrigger (from a CDN).
Sticky does the stacking
Each card is position: sticky with the same top offset, so as you scroll, a card sticks at that position while the next card scrolls up underneath the previous one's bottom and eventually pins over it. CSS sticky alone produces the overlap for free — no JavaScript needed for the pinning. The cards share a top value so they land in the same place and pile up.
GSAP adds the depth
Sticky alone would just stack flat cards; the recession comes from GSAP. For each card, a tween scales it to 0.86 and dims it with filter: brightness(0.6), driven by a ScrollTrigger whose trigger is the next card. So a card only shrinks while the card after it is moving up to cover it — start: 'top bottom' (next card enters) to end: 'top top' (next card fully overlaps). The result is each card visibly sinking back as it's buried, giving the stack real depth.
Triggering off the next element
The key idea is that each card's animation is keyed to the next card's scroll position, not its own. That's what synchronizes the shrink with the cover: the card behind reaches full small-and-dim exactly when the card in front has completely overlapped it. transform-origin: 50% 0 scales each card from its top edge so it shrinks toward where it's pinned, keeping the top aligned as it recedes.
Scrubbed and reversible
scrub: true and ease: 'none' tie the scale and brightness directly to scroll, so scrolling back up brings each buried card forward again — it grows and brightens as the covering card retreats. Nothing plays on a fixed timeline, so the stack is fully reversible and always matches the scroll position.
Cheap and smooth
The animation only changes transform and filter, both GPU-friendly, and the last card is skipped since nothing ever covers it. Because sticky handles layout and GSAP only animates compositor properties, the effect stays smooth with any number of cards.
Customizing it
Add cards (each with its own accent), change how small or dim they get, adjust the sticky top and card heights, or add a slight y offset for a fanned look. Pair it with stacking scroll cards, a scroll pin steps panel, or scroll 3d cards.
Build with AI
Build, Understand, Optimize, and Extend It With AI
You don't have to reason through the trigger-off-the-next-card trick alone. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why each card's shrink-and-dim tween is keyed to the next card's ScrollTrigger rather than its own scroll position, or why transform-origin: 50% 0 is essential for the recession to look correct against a sticky top offset. The same assistant can help optimize it — asking whether the 0.86 scale and brightness(0.6) targets should vary per card for a more dramatic deep stack, or whether the last-card skip logic would need adjusting if cards were added or removed dynamically. It's also useful for extending the effect: ask it to add a slight rotation or horizontal offset as each card recedes for a fanned-deck look, layer a subtle box-shadow growth as cards go further back, or make the stack pause on a specific card when linked to from an anchor. Treat the code less like a finished artifact and more like a starting point for a conversation.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a "scroll sticky stack" card effect in plain HTML, CSS, and JavaScript using CSS position: sticky for the stacking and GSAP with its ScrollTrigger plugin (load both from a CDN) only for the depth/recession animation.
Requirements:
- A vertical sequence of full-height card elements, each using position: sticky with the exact same top offset value, so CSS alone causes each card to pin in place while the next one scrolls up and overlaps it — no JavaScript should be responsible for the stacking/pinning itself.
- Give every card transform-origin: 50% 0 (scaling from its top edge, not its center), since it is pinned at a fixed top offset and must shrink toward that same point to look anchored rather than drifting.
- For every card except the very last one (which nothing ever covers, so it must be skipped), create a GSAP tween that scales it down to roughly 0.86 and dims it using a CSS filter brightness value less than 1.
- Critically, each of those tweens' ScrollTrigger must use the NEXT card in the sequence as its trigger element (not the card being animated itself), starting when the next card's top reaches the bottom of the viewport and ending when the next card's top reaches the top of the viewport — so a card only recedes exactly while the card behind it is sliding up to cover it.
- Use scrub: true and ease: none on every tween so the recession is scrubbed directly to scroll position in both directions, meaning scrolling back up must bring a buried card forward again (growing and brightening) as the covering card retreats, with no separate reverse code.
- Only animate transform (scale) and filter (brightness) properties, both GPU-friendly, so the effect stays smooth regardless of how many cards are in the stack.Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
Step by step
How to Use
- 1Add the GSAP CDNsInclude gsap and ScrollTrigger from the CDN panel.
- 2Paste HTML, CSS, and JSFour tall cards render in a stack.
- 3Scroll downEach card pins, then shrinks as the next covers it.
- 4Scroll back upBuried cards grow and brighten again.
- 5Add a cardDrop in another .ss-card with an accent.
- 6Tune the recedeChange the scale and brightness targets.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
CSS does the stacking: each card is position: sticky with the same top offset, so a card sticks while the next scrolls up and pins over it. That overlap is free, with no JavaScript. GSAP adds only the depth — scaling and dimming each card as it is covered — so the two work together.
Each card's tween is triggered by the next card, not itself: from start: top bottom (the next card enters) to end: top top (the next card fully overlaps). So a card reaches its smallest, dimmest state exactly when the card in front has completely covered it, which is what makes the recession read correctly.
transform-origin: 50% 0 scales each card from its top, which is where it pins. As the card shrinks it stays aligned to its sticky position instead of drifting toward its center, so it cleanly recedes behind the covering card with the top edges matching.
Yes. scrub: true and ease: none tie the scale and brightness directly to scroll, so scrolling up brings each buried card forward again — it grows and brightens as the covering card retreats. Nothing plays on a fixed timeline, so the whole stack tracks scroll position in both directions.
Render the cards with position: sticky in CSS, then in a mount effect register ScrollTrigger and loop the card refs, creating each tween triggered by the next card. Return a cleanup that reverts the GSAP context. If cards are dynamic, refresh ScrollTrigger after they render. The sticky CSS ports unchanged.