Skip to content

GSAP & Scroll Motion

Sticky Stacked Testimonial Cards on Scroll

Cards pin with CSS position: sticky and each one scales back as the next slides over it, so the stack is native scroll plus a scrubbed transform: no pinning spacers, no layout shift.

60fps · Zero CLS

Works in Webflow Framer React Zero CLS

Customize before you copy

Platform
Motion timing

Showing the Webflow version

Claude prompt · production spec
You are a senior creative developer. Build a "sticky stacked cards" testimonial section.

Behaviour:
- 4–6 testimonial cards in a vertical list. Each card sticks to the viewport with CSS position: sticky; card i sticks at top: calc(12vh + i * 24px), so earlier cards peek out above later ones like a deck.
- As card i+1 scrolls up over card i, scrub card i down to scale 0.92 and opacity 0.6 (transform-origin: top center). The last card never shrinks.
- The scrub runs from the moment the NEXT card enters the viewport until it reaches its own sticky offset, with 0.8s of smoothing.

Hard constraints:
- Animate transform and opacity only. Never animate top, height, margin or filter.
- Do NOT pin with JavaScript: sticky positioning does the pinning, so there are no pin-spacers and zero CLS. No ancestor of the cards may have overflow: hidden (it silently breaks sticky).
- Reduced-motion users get the plain sticky stack with no scrub.
- Add will-change: transform only while a card is animating, never permanently.
- Semantic markup: a <section> with an aria-labelledby heading, each card a <figure> with <blockquote> and <figcaption>.

Deliver the structure, the CSS and the script with a cleanup, then tell me which three values to tweak for a tighter or looser deck.

Target platform: Webflow.
- Build the structure as native Webflow Designer elements with Client-First class names (section_[name], [name]_component, [name]_item). No div soup from an HTML embed unless I ask for one.
- Hook every behaviour to custom attributes (data-gsap="…"), never to class names, so designers can restyle without breaking the script.
- Load GSAP through Webflow's built-in GSAP integration (Site settings) or the jsDelivr CDN tags, and put the init script in Page settings → Before </body> tag, wrapped in Webflow.push(() => { … }).
- Say which parts go in Designer styles, which in a page-head <style>, and which in the body script.
- Designer structure: section_testimonials > testimonials_list (data-gsap="stack-list") > testimonials_card (data-gsap="stack-card") ×4–6. The script sets each card's --i, so editors can add or remove cards freely (a CMS list works too).
Motion timing: "Editorial". Use a base duration of 0.8s, ease "expo.out" (CSS: cubic-bezier(0.16, 1, 0.3, 1)), stagger 0.08s, scrub smoothing 0.8, and springs of stiffness 220 / damping 22, everywhere a duration, ease or spring appears.

3-step implementation guide

  1. Step 1

    DOM & attribute setup

    Lay the cards out as a vertical list with a large gap (about 40vh) and make each one position: sticky with a top offset that grows by 24px per card. Check that no parent has overflow: hidden, or sticky silently stops working.

  2. Step 2

    Prompt Claude or drop in the snippet

    Paste the Claude prompt with your platform selected to get a version shaped for your stack, or drop in the snippet as is. The only JavaScript is a scrubbed scale and opacity on the card being covered.

  3. Step 3

    Mobile & Core Web Vitals check

    On a phone, scroll the whole stack and confirm nothing jumps: CLS should read 0 in PageSpeed Insights. Turn on reduced motion and check the cards still stack, just without the shrink.

Building a full site like this?

Skip the manual setup — I ship complete Figma-to-Webflow & Framer builds in 5–10 business days, or can wire this exact interaction into your live site in 48 hours ($250).