Skip to the content

Stack cards

Full width cards that stack on top of one another as the page scrolls.

Become a member to unlock the full effect today.

Join now

Already a member? Sign in

Documentation

  1. Copy to Webflow

    Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: Webflow removes any font your site has not installed.

  2. Add custom CSS

    Three things belong to the page rather than to the component, and the pile needs all three: a card needs an opaque background, or the pile is see through; a card needs a height, or enough content to be tall; and the bottom padding of the track is how long the last card holds the screen before the page moves on.
  3. Add custom JS

  4. Tune it

    Custom attributes
    Select the section on the canvas and open the Settings panel. Under Custom attributes, add a pair: the name on the left, the value on the right.
    Custom attributeWhat it does
    data-stack-cards Marks the track, the block that holds the cards. It takes no value: leave the value field empty. Without it nothing is mounted, and the boot of the embed falls back to the section it was pasted in, which only works when the cards are that section’s own children.
    data-stack-cards-card Marks one card. It takes no value. Every card carries it, and every card is a direct child of the track. Without it on any of them the engine takes the track’s own children as the cards, leaving out anything holding a script, and says so once in the console; a card that is a grandchild is never found either way. [ Optional ]
    data-stack-cards-state Written by the engine on the track while the pile is in the window, with the value active, and removed when it leaves. Never written by hand: it is what the stylesheet reads to know it may scale and dim a card, so a pile nobody is looking at carries no transform and no filter. [ Optional ]
    Settings
    Every setting is a custom attribute too, added the same way and on the same section. An attribute always wins over the defaults written in the code.
    AttributeDefaultWhat it is
    data-stack-cards-top clamp(12px, 3vh, 40px) Where a card stops, counted from the top of the window; the place for the height of a fixed header.
    data-stack-cards-step clamp(4px, 0.6vw, 10px) How much lower each card stops than the one before it, which is what gives the pile a visible edge.
    data-stack-cards-depth 0.08 How much a card shrinks while it is being covered, as a share of its size.
    data-stack-cards-dim 0.3 How much light a card loses while it is being covered.
    data-stack-cards-blur 0 How blurred a card is once it is covered, in pixels.
    data-stack-cards-enter 1 Where the receding starts, as a share of the window height measured from the top: 1 is the bottom edge.
    data-stack-cards-ease none The shape of the receding across that travel. Options: any GSAP ease name, none (even with the scroll), power1.out, power2.inOut, and so on.
    data-stack-cards-scrub 0 How long the cards take to catch up with the scroll, in seconds.
    data-stack-cards-debug false Writes the state, the card count and the pin line in data-stack-cards-debug-* attributes. Options: false, true.

What it does

Stack cards is a scroll animation for Webflow and vanilla JavaScript, built on GSAP 3 and ScrollTrigger. Also called sticky stacking cards, stacking cards on scroll or stacked cards scroll.

Full width cards that stack on top of one another as the page scrolls. Each card stops under the one before it and holds the screen while the next one climbs over it; the card underneath falls back, a little smaller and a little darker, the way a card is put down on a table. At the end of the pile the section lets go and the page carries on. The pin is the page's own sticky positioning, not a scripted one: a sticky card never leaves the flow, so the page is exactly as tall before, during and after, and there is no spacer to insert and no height to hand back, which is where a scripted pin jumps. GSAP and ScrollTrigger drive one number per card, how covered it is, and the stylesheet turns it into a scale, a brightness and a blur. The content of a card stays live the whole way: reading order, tab order, selection and search are the ones the markup has. Pattern type stacked cards, sticky cards, card deck on scroll.

Updated

Questions

Add the custom attribute data-stack-cards to the block that holds the cards and data-stack-cards-card to each card, under Custom attributes in the Settings panel. The cards have to be children of that block, in the order they should stack: a card that is a grandchild is never found.

The pin is CSS position: sticky, not ScrollTrigger's pin, so no spacer is inserted and the page is as tall pinned as it is at rest. GSAP 3.12.5 and ScrollTrigger, loaded from the CDN, only drive how much a covered card shrinks, darkens and blurs. Without them the cards still pin.

Look for an ancestor with overflow: hidden: it becomes the scroll container of every sticky card inside it, and a container that does not scroll has nowhere to pin. Use overflow-x: clip on that ancestor. The engine walks up the tree at mount and names it in the console.

data-stack-cards-depth is how much a covered card shrinks, 0.08 by default, and data-stack-cards-dim is how much light it loses, 0.3 by default. Lower values keep the card its size and the pile evenly lit; higher values make it fall right back and go to black. data-stack-cards-blur adds a blur in pixels and is 0 by default.

Give top the height of the header, for example data-stack-cards-top="calc(72px + 1rem)", and the cards stop under it. top is where a card stops, counted from the top of the window, and takes any CSS length; its default is clamp(12px, 3vh, 40px).