Back to library
INTERACTION_116

Horizontal Gallery Reveal.

A gallery track slides sideways while images uncover in turn. Each image clipped from the left at 0 opacity before the trigger; opening each image clip as it enters the visible track once the gallery entering view, then horizontal scroll.

CATEGORY
Images
COMPLEXITY
Easy
TECH
CSS
PLATFORM
Both
PERFORMANCE
Medium
LIVE PLAYGROUND
CSS / CSS
/* Horizontal Gallery Reveal — A gallery track slides sideways while images uncover in turn. */
.horizontal-gallery-reveal {
  --dur: 700ms;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --stagger: 110ms;
  will-change: transform, opacity;
}

.horizontal-gallery-reveal > * {
  opacity: 0;
  transform: translateY(14px);
  animation: horizontal-gallery-reveal-in var(--dur) var(--ease) forwards;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}

/* each image clipped from the left at 0 opacity -> opening each image clip as it enters the visible track */
@keyframes horizontal-gallery-reveal-in {
  to {
    opacity: 1;
    transform: none;
    filter: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .horizontal-gallery-reveal > * {
    opacity: 1;
    transform: none;
    animation: none;
  }
}
React / TSX
import { useEffect, useRef } from "react";

/** Horizontal Gallery Reveal — trigger: the gallery entering view, then horizontal scroll */
export function HorizontalGalleryReveal({ children }: { children: React.ReactNode }) {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
      el.dataset["state"] = "in";
      return;
    }
    const io = new IntersectionObserver(
      ([entry]) => {
        if (entry?.isIntersecting) {
          el.dataset["state"] = "in";
          io.unobserve(el);
        }
      },
      { threshold: 0.2 },
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);

  return (
    <div ref={ref} className="horizontal-gallery-reveal" data-state="out">
      {children}
    </div>
  );
}

IF YOU LIKE THIS, STEAL THESE TOO.

INTERACTION_105CSS

Image Mask Reveal

The image uncovers behind a mask while it settles from a slow zoom.

Images / LightView
Media
INTERACTION_107CSS

Parallax Image

The image drifts slower than the frame that contains it.

Images / LightView
Media
INTERACTION_108CSS + JS

Cursor Zoom

The image magnifies around the exact pointer position.

Images / LightView
Hover to play
INTERACTION_112CSS

Hover Video Preview

A muted loop fades over the poster image on hover.

Images / MediumView