Back to projects
Oct 2025
3 min read

Pure CSS Scroll-Driven Stacked Cards Animation

A performant stacked cards animation using the CSS scroll-driven animations API.
  • CSS
  • Scroll-Driven Animations
  • Vite

I’ve always been fascinated by modern CSS capabilities and how they can create interactive, performant experiences. For years, I wasn’t the kind of frontend developer much interested in web animations. Page speed and user experience were always more important to me than flashy effects. But pure CSS scroll-driven animations may have changed my perspective entirely.

The Power of CSS-Only Animations

This stacked cards demo showcases what’s possible with pure CSS using the new animation-timeline property. No JavaScript required for the core animation logic—just clean, declarative CSS that’s both performant and maintainable.

How It Works

The implementation leverages several modern CSS features working together:

Sticky Positioning & CSS Custom Properties

Each card uses position: sticky with calculated offsets based on CSS custom properties:

.card {
	position: sticky;
	top: var(--sticky-position);
	padding-top: calc(var(--index) * var(--card-top-offset));
}

The --index custom property creates a staggered effect, where each card has a slightly different top offset.

Note: I could have used the upcoming sibling-index() function instead of manually setting the index for each card, but browser support is still limited. This would allow for a more dynamic approach where the index is automatically calculated based on the element’s position among its siblings.

Scroll-Driven Animation Timeline

The magic happens with the animation-timeline property, which ties animations directly to scroll progress:

#cards {
	view-timeline-name: --cards-element-scrolls-in-body;
}

.card__content {
	animation: linear scale-down forwards;
	animation-timeline: --cards-element-scrolls-in-body;
	animation-range: exit-crossing var(--start-range) exit-crossing var(--end-range);
}

Each card scales down as it exits the viewport, with timing calculated based on its position in the stack.

Progressive Enhancement

The demo includes a browser support check and graceful degradation:

@supports (animation-timeline: view()) {
	/* Scroll-driven animations only apply when supported */
}

Users with unsupported browsers still get the basic stacked layout—just without the scroll animations.

Interactive Controls

While the core animation is CSS-only, the demo includes a Tweakpane control panel built with JavaScript that lets you experiment with:

  • Card height and spacing
  • Sticky positioning
  • Different animation presets
  • Debug mode for development

This creates an interactive playground perfect for understanding how each property affects the final result.

Why This Matters

This project demonstrates that modern CSS can handle complex animations that previously required JavaScript, resulting in:

  • Better performance - Animations run on the compositor thread
  • Reduced JavaScript bundle size - Less code to ship to users
  • Improved accessibility - Respects user motion preferences automatically
  • Cleaner architecture - Animation logic lives in CSS where it belongs

The web platform continues to evolve, and CSS scroll-driven animations represent a significant step forward in creating performant, interactive experiences with less complexity.