← The library

Focus gallery

A vertical gallery driven by the scroll

Free

What's included

A vertical gallery in which the centred image comes forward: it grows by half again and returns to full opacity, while the others fall back to 0.7 and fade. The movement isn't an animation started by hand, it's the scroll itself.

Two files, plus your images: a stylesheet and a script. No dependencies, no build step, no external requests. The six photographs shipped were generated for this folder and are royalty-free — nothing to download, nothing to credit.

The surprising part is what the script doesn't do. The scroll run, the centring of each image and the keyboard traversal are written in CSS, in a single padding declaration. The script decides one thing only: which of the images is in the centre.

Features

  • The scroll does everything — half a viewport of padding top and bottom, and the first image is already centred at rest, the last one at the end of the run. Not one height calculation in JavaScript.
  • Click and keyboard — clicking an image brings it back to the centre; the arrow keys, Home and End do the same, and focus always drags the image along with it.
  • Works without JavaScript — the layout holds together completely, and the scroll settles onto each image by itself with scroll-snap.
  • One variable for the scale — image, corner radius, gaps, shadows and text all derive from the same reference size, and follow together.
  • An event to hook intofocus-gallery:change gives the index of the centred image, enough to show a caption or a counter.
  • Any number of images — six, three or forty: neither the CSS nor the script knows the count.

Dropping it into a page

Two files to load, then a list of images:

<link rel="stylesheet" href="focus-gallery.css">
<script src="focus-gallery.js" defer></script>
<section class="focus-gallery" aria-labelledby="galerie-titre">
  <h2 class="focus-gallery__titre" id="galerie-titre">The thread of images</h2>
  <p class="focus-gallery__note">Driven by the scroll</p>
  <div class="focus-gallery__vue">
    <ol class="focus-gallery__rail">
      <li class="focus-gallery__cellule">
        <button type="button" class="focus-gallery__cadre">
          <img class="focus-gallery__image" src="images/balloon.webp"
               width="900" height="600"
               alt="A striped hot-air balloon above a valley of mist">
        </button>
      </li>
      <!-- as many <li> as there are images -->
    </ol>
  </div>
</section>

The script installs itself, including on a gallery inserted after load. The height is set through the --fg-hauteur variable and not through height: it also commands the run.

What you should know

  • The gallery takes over the scroll for its own height. That's the principle: the wheel crosses it image by image, then hands control back to the page on its own. On a page that puts two of them back to back, give them some room.
  • The scrollbar is hidden. It is on the original model too, and that's the price of the composition: nothing visually says there are more images. The nearest neighbour, though, always sticks out far enough to say so.
  • The two pieces of text aren't selectable. They're laid over the scrolling area; without pointer-events: none, the wheel passing over them wouldn't scroll anything.
  • No inline styles, no inline scripts. The component honours the site's strict security policy and never uses innerHTML — checked by serving it over HTTP with the header, not assumed.
  • The design comes from elsewhere. The proportions, the two scales, the shadows and the motion curve follow those of a commercial Framer component, measured on the published page. The code, the images and the text are original: nothing was taken from its implementation.

Take it, open it, break it.

This component is free. The full library — the templates and the other components — comes with the subscription, alongside the course.

Immediate access · No commitment · Cancel in one click