
What is “Scroll Snap”?
Scroll Snap is pretty much what it sounds like — snapping or locking in to a certain position while scrolling. So, when scrolling through content like sections of a website or an image gallery, we often like to have whatever we’re scrolling through lock or snap in a particular position as a means of assisting with scrolling.
A great example would be iTunes’ Cover Flow view.

Usage
Pure CSS Scroll Snap uses properties which are a part of the CSS Scroll Snap Module. The system is based on a parent-child relationship between divs (as we’ll see in the following example) and uses the CSS properties — scroll-snap-type
and scroll-snap-align
respectively.
.parent { scroll-snap-type: x mandatory; } .child { scroll-snap-align: start; }
Now, let’s go ahead and set up our workspace. For our example, we’ll be using a very basic, stripped-down, non-fancy version of the Cover Flow view. As we scroll horizontally through the X-axis, we can scroll through images and their captions to scroll and lock in onto the center of our screen. We’ll use images from UnSplash and use some dummy text for the captions.
Let’s look at the code.
HTML
<div class="parent"> <div class="child"> <img src="https://source.unsplash.com/random/"/> <div class="caption"> <h3>Caption One</h3> <p>Far far away, behind the word mountains, far from the countries Vokalia and Consonantia, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean. A small river named Duden flows by their place and supplies it with the necessary regelialia.</p> </div> </div> </div>
The div element with a class of .parent
is our parent element. The .child
div element is, you guessed it — the child. Inside this child element, we’ve set an image. Below this image is a .caption
div element which contains a header and paragraph. For this example, we’ll duplicate the .child
div 4 more times to make 5 slides.
CSS
body { font-family: sans-serif; font-size: 16px; font-weight: 300; background-color: #151515; margin: 0; height: 100vh; color: #fff; } p { max-width: 60%; line-height: 1.25rem; padding-left: 1rem; border-left: 2px solid rgba(255, 255, 255, 0.25); }
For the body, you can see we’ve done nothing fancy. All we have here is a full viewport height of 100vh
, reset the default browser margins, and set a background color because… why not?
For the paragraph, we’ve added a bit of left padding and a border to make it a little fancy. We’ve also set a max-width
so that we don’t have too many words on a single line, therefore maintaining readability.
Let’s start with styling the .parent
element.
.parent { display: flex; padding: 1rem; width: 80%; height: 100%; margin: 0 auto; background-color: #000; overflow-x: scroll; scroll-snap-type: x mandatory; }
Most of the CSS you see here are basic styling except that we’ve used display: flex
because we’re going to be using the CSS property flex-grow
in the .child
elements. The overflow
property is used to hide spillovers the contain the .child
elements within the set boundaries of the .parent
. Also, without it, the snap functionality won’t work.
Now here’s the key player: the scroll-snap-type
. This property accepts two arguments — the first is either x
or y
— which is either the x-axis or the y-axis. The second is the one we’ll stick to for this example, which is mandatory
. This will make sure the child element locks back in place if you scrolled just a tiny bit. Larger scrolls amounts will snap you to the next slide. For more options, you can visit MDN Web Docs.
Now let’s see the CSS for .child
element(s).
.child { position: relative; margin: 0.5rem; border-radius: 10px; scroll-snap-align: center; }
Here, the position
has a value of relative
because the .caption
div within will require a position
of absolute
. The margin
is to create some space between each child element.
The key CSS for the .child
element is the scroll-snap-align
property. This property accepts up to two values for each the x and y axes, or block or inline, but we’re just going to be using one value, and here, we’ve used center
(remember, we wanted to position the child elements at the center of the screen). Optionally, you could use start
or end
to position them.
Using the following CSS, we’re simply going to —
- style up the images so that they fit nicely inside the
.child
elements - style and position the
.caption
div while also giving it a fixed height for uniformity - style each of the
.child
elements using:nth-child()
to give them different widths usingflex-grow
.
.child img { width: 100%; height: 100%; object-fit: cover } .child .caption { position: absolute; bottom: 0; padding: 1rem; height: 210px; background-color: rgba(0, 0, 0, 0.5) } .child:nth-child(1) { flex: 0 0 100% } .child:nth-child(2) { flex: 0 0 80% } .child:nth-child(3) { flex: 0 0 100% } .child:nth-child(4) { flex: 0 0 50% } .child:nth-child(5) { flex: 0 0 100% }
And now this is what our browser output should look like (sans the image):

Browser Support
Global browser support for Scroll Snap is at 92.07%. For more information, you can look up CanIUse.
And there you have it! It’s that simple and easy!