A woman in a white dress floating in the water, seen from beneath the waves A swarm of blue jellyfish A young woman's face, eyes closed, seen underwater with her hair floating around her face Blue ocean depths

Scroll the gallery window

There’s a problem with scrolling on the web. On sites with large fullscreen designs - pages vertically divided into distinct sections, each intended to take up the full area of the browser window - it’s easy to scroll to a point halfway between two sections, throwing the off page interaction. Smaller scrolling UI components often have this issue too. What we want is for each section to automatically slide into place when user interaction brings them close enough.

Traditionally this problem was solved with JavaScript (usually in a framework such as JQuery), but the same functionality is now built into CSS, via Scrolling Snap Points (current draft).

The Concept

Let’s say we have a series of images arranged vertically in a container. In this case, the container is a <figure> element which is further wrapped inside a <div>:

<div id="scrollcontainer">
    <figure>    
        <img src="floating-2x.jpg" alt>
        <img src="jellyfish-2x.jpg" alt>
        <img src="silk-2x.jpg" alt>
        <img src="the-deep-2x.jpg" alt>
    </figure>
</div>

The outer <div> has been sized to fit around just one image exactly using the standard technique of employing relative and absolute positioning to preserve an intrinsic aspect ratio:

#scrollcontainer {
    font-size: 0;
    position: relative;
    padding-top: 66%;
}
#scrollcontainer figure { 
    margin: 0;
    position: absolute;
    top: 0;
    width: 100%;
    height: 100%;
}

While the figure element is set to the height of its container, the other images will continue to show beyond the bounding area of the box, since web pages won’t hide ] content by default, even if it overflows a container. To change that behaviour, we must set the overflow property of the figure:

#scrollcontainer figure { 
    overflow: auto;
}

Now the container scrolls up and down, but can stop at any point, including halfway between two pictures; we want a scroll or swipe behaviour to “snap” the image column to the nearest photo.

CSS Scrolling Snap Points

To start, we must set the scroll-snap-type on the container:

#scrollcontainer figure 
    scroll-snap-type: mandatory;
}

The mandatory value means that the container must come to rest at a scroll snap point after a scroll or swipe behaviour. There is also a proximity value, which means that snapping will only occur if the current position is sufficiently close to a snap point (proximity is not yet supported in most browsers, as of this writing).

Next, we must set the scroll-snap-points value. In this case, the images are in a column, so we’ll use the scroll-snap-points-y property, with repeating value of 100%, representing repeated units of the container’s height.

#scrollcontainer figure 
    scroll-snap-points-y: 100%;
}

Coordinates & Destinations

There are two other properties we must deal with: scroll-snap-coordinate and scroll-snap-destination. The former is applied to the elements we want to “stick” during the scroll, while the latter is applied to the nearest ancestor does not scroll itself. In our case, the code looks something like this:

#scrollcontainer figure { 
    scroll-snap-destination: 50% 50%;
}
#scrollcontainer img {
    scroll-snap-coordinate: 50% 50%;
}

Essentially, these two values “map” each image to a point inside the scrolling container: the center of each photograph should stick to the exact center of its container. There are other possibilities, of course: making the scroll horizontal, rather than vertical (which would just require changing scroll-snap-points-y to scroll-snap-points-x; diagonal snap-scrolling, and moving elements of different sizes. I’ll cover these applications and more in future articles.

Unfortunately, Safari currently has a different interpretation of this value, and so is listed seperately with a a href="/217/CSS-Vendor-Prefixes-and-Flags">vendor prefix:

#scrollcontainer figure { 
	-webkit-scroll-snap-destination: 100% 100%;
}
#scrollcontainer img {
    -webkit-scroll-snap-coordinate: 50% 50%;
}

Support, Prefixes & Polyfills

Support for CSS Snap Points is fairly good across modern browsers: Firefox has full support, and Safari (desktop and iOS) implementation has a few limitations. Perhaps suprisingly, Microsoft has supported CSS Scroll Snap Points since IE10, under a -ms prefix. IE11 and Edge support the API on all screens (IE10 only supported it on touch screens.)

For browsers without support, I’d recommend Clemens Krack’s scrollsnap-polyfill, as has no dependencies (other than polyfill.js), uses requestAnimationFrame for movement, and has a nice little added “bounce” on the snaps.

Photographs by Elena Kalis, Yarik.OK and Sergiu Bacioiu, licensed under Creative Commons.

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/XXGqZB