GSAP ScrollTrigger List Expansion
See the Pen GSAP ScrollTrigger List Expansion.
Tech & Dependencies
Features
- ✓ ScrollTrigger
- ✓ Card Stack Effect
- ✓ CSS Clip-path
- ✓ Responsive Mobile Mockup
Browser Support
Core
This snippet showcases a GSAP ScrollTrigger List Expansion effect. It mimics the native iOS “Notification Center” or “Wallet” card stack behavior. Its function is to condense a long list of items into a compact, layered visual stack, and then fluidly expand them into full, scrollable cards as the user scrolls down the container, creating a highly tactile mobile UI experience.
Specs
- Weight: ~80 KB (Requires GSAP core and ScrollTrigger plugin).
- Performance: Highly optimized. The GSAP timelines target CSS custom properties which are then mapped to hardware-accelerated
transformandclip-pathproperties in the SCSS, preventing heavy layout thrashing during scroll. - Theming / Customization: Core colors are managed via CSS variables. The iPhone mockup wrapper drops away automatically on smaller screens (
max-width: 500px) for a native full-screen experience. - Responsiveness: Designed primarily as a mobile view (
width: 375px). On desktop, it renders inside a CSS-drawn iPhone frame. - Graceful Degradation: Relies heavily on GSAP and JavaScript. Without JS, the cards will render, but they will remain stuck in their initial, overlapped state, making the content unreadable.
Anatomy
The component uses a clever layering system to create the “stacked” illusion.
- HTML (The Skeleton): An outer
#phonecontainer holds the.screenand status bar icons. Inside, the.contentdiv acts as the scroll container. The.entrieswrapper holds multiple<article>tags. Each article has a.compact(the folded top edge) and an.inner(the actual content). - CSS (The Skin): SCSS handles the complex transformations. The
.entries articleusesposition: stickyto keep them anchored while scrolling. CSS variables set the initial stacked offset.clip-pathis used to hide the bottom portion of the cards initially. - JS (The Nervous System): Iterates over the
<article>nodes and usesGSAP.timelineandScrollTrigger.create. It binds the scroll position to the animation of the CSS variables, causing the cards to un-clip, scale up, and un-rotate as they hit specific trigger points.
Logic
The standout technical implementation is the “Scroll-Scrubbed Custom Property Routing”.
function roll(content, article, articles, index) {
let animation = timeline().to(article, {
'--clip': `${article.offsetHeight + 112}px`,
'--compact-s': 1,
'--compact-o': 1,
// ...
});
// ...
return ScrollTrigger.create({
animation,
trigger: article,
scroller: content,
scrub: true,
start: `top top+=184`,
end: `bottom top+=112`
});
}
Instead of letting GSAP directly manipulate inline styles like transform: translateY(...) (which can get messy when dealing with complex 3D rotations and clipping simultaneously), the script animates custom CSS variables. GSAP smoothly interpolates --clip from 0px to the full height of the article. The SCSS then reads clip-path: polygon(0 var(--clip), 100% var(--clip), ...) to reveal the card. Tying this timeline to a ScrollTrigger with scrub: true means the animation frame is inextricably linked to the user’s scrollbar position, allowing them to drag the animation forward and backward seamlessly.
Feel
Tactile, elastic, and deeply satisfying. The interaction feels less like scrolling a webpage and more like physically pulling apart a deck of cards. The use of position: sticky ensures the stack feels grounded, while the staggered rotation gives the folded cards a slight, messy realism before they snap perfectly into place. The dynamic header fading provides a polished cinematic finish to the scrolling journey.


