Advertisement

Scroll-Driven Image Swapper

| by Vladimir | 2 min read | code by Jhey Tompkins
Advanced

Tech & Dependencies

HTML CSS Babel
GSAP ScrollTrigger

Features

  • Scroll-Linked Animation
  • Image Crossfade
  • Polyfill Strategy
  • Responsive Grid

Browser Support

Chrome 115+ Edge 115+. Firefox/Safari (via GSAP Polyfill)

Core

This Scroll-Driven Image Swapper demonstrates the bleeding edge of web animation. It uses the native CSS Scroll-driven Animations API to create a complex parallax-like effect where two columns of different heights scroll in sync. As you scroll, the images in the shorter column slide and crossfade to match the context of the taller column. Crucially, the code implements a Progressive Enhancement strategy: it checks for native browser support and falls back to GSAP ScrollTrigger for browsers that haven’t implemented the spec yet.

Core Technique

The native implementation relies on view-timeline and animation-timeline. The parent container defines a named timeline, and the child elements (the swapper panel and the images inside) bind their animation progress to it.

  1. Named Timeline: The .image-box container gets view-timeline: --container. This allows children to track its position relative to the viewport.
  2. Synchronized Translation: The .swapper (the moving panel) uses animation-timeline: --container. The CSS calculates exactly how far it needs to move (--catch-up) so that the top and bottom align perfectly with the taller column at the start and end of the scroll.
  3. Image Crossfade: Images inside the swapper use animation-timeline: view() with an animation-range. This triggers their opacity fade exactly when they enter or leave the central “sweet spot” of the screen.

Customization

The layout is mathematically rigid to ensure alignment. To customize dimensions, focus on the CSS variables in the :root.

:root {
  /* Padding from the left side */
  --left-pad: calc(48px + 2rem);
  
  /* Ratios for the two columns */
  --column-one: calc(var(--container-width) * (1.2 / 3.2));
  --column-two: calc(var(--container-width) * (2 / 3.2));
  
  /* Height constraints */
  --col-one-height: min(70vh, ...); 
}

/* Adjusting the animation trigger points */
.swapper img {
  /* Start fading in at 45%, finish fading out at 55% of viewport */
  animation-range: cover 45% cover 55%;
}

Tips

1. The Polyfill Strategy: The JavaScript block starts with if (!CSS.supports('animation-timeline: scroll()')). This is a vital pattern. It ensures that Chrome/Edge users get the performant, main-thread-free CSS animation, while Safari/Firefox users get the robust (but JavaScript-dependent) GSAP version.

2. Isolate Stacking Context: The .swapper class uses isolation: isolate. This is crucial when using mix-blend-mode on images (as seen in the 3rd section). Without isolation, the blend modes might interact with the background of the entire page rather than just the container.

Advertisement