Advertisement

CSS Scroll-Driven Masonry Reveal

| by Vladimir | 2 min read | code by Adam Argyle
A11y Ready Intermediate

Tech & Dependencies

HTML CSS
Open Props (CSS Library)

Features

  • Scroll Triggered
  • Staggered Entrance
  • Responsive Grid
  • Reduced Motion

Browser Support

Chrome 115+ Edge 115+ Safari 26+ Firefox (flag/polyfill)

Core

This Scroll-Driven Masonry Reveal creates a playful, tactile experience where content cards appear to be “dealt” onto the screen as the user scrolls. By leveraging the native CSS Scroll-driven Animations API, it achieves smooth, main-thread-free entrance effects without a single line of JavaScript. The layout adapts intelligently from 2 to 8 columns, making it a robust solution for image galleries or blog archives.

Core Technique

The animation logic is built on CSS Variables and the view() timeline.

  1. View Timeline: The .card-animation-layer uses animation-timeline: view(). This binds the animation’s progress directly to the element’s position within the viewport.
  2. Animation Range: animation-range: cover 0% contain 15% dictates that the animation starts the moment the element enters the viewport and completes when it is 15% visible.
  3. Procedural Randomness: Instead of random JavaScript numbers, the CSS uses nth-of-type selectors to assign different values to --side (rotation direction) and --amp (rotation amplitude) based on the column count. This creates a “random” look that is actually deterministic and performant.

Customization

The motion logic is encapsulated in the CSS variables assigned to the grid items. You can tweak the intensity of the “deal” effect by modifying the rotation calculation or the slide-in keyframes.

/* Adjust the animation physics */
@keyframes slide-in {
  from {
    scale: .85; /* Start size */
    /* Rotation logic: Side (+/-1) * (Base Angle * Multiplier) */
    rotate: calc((var(--side, 1) * (5deg * var(--amp, 1))));
  }
}

/* Modify the timeline trigger */
.card-animation-layer {
  /* 
     cover 0%: Starts exactly when top edge touches viewport bottom 
     contain 15%: Ends when item is slightly inside 
  */
  animation-range: cover 0% contain 15%;
}

The grid responsiveness is handled via a CSS variable --cols inside media queries.

main {
  --cols: 2; /* Mobile default */
  /* ... */
  @media (width >= 1200px) { --cols: 6 } /* Desktop */
}

Tips

1. Browser Support Strategy: This code relies on animation-timeline, which is currently supported in Chromium-based browsers (Chrome, Edge). For Firefox and Safari, the layout will simply render the static cards without the scroll effect (Graceful Degradation). If animation is critical, use a polyfill like scroll-timeline-polyfill.

2. Open Props: This snippet imports Open Props via CDN for normalized styles and variables (var(--size-5), var(--surface-2)). If you copy this code, ensure you either include the Open Props import or replace the variables with your own CSS values.

Advertisement