As front end developers, we often get excited about some pretty niche things.

Take scrolling for instance. Remember when scroll inertia came along? We'd be excitedly flicking through websites shouting "Look! It has momentum! It has MOMENTUM!" And people are looking at us like:

Katt Williams looking confused

Well, CSS scroll snap is the latest innovation in the fascinating world of website scrolling. The next stage in its character arc, if you will.

Unlike scroll inertia, which loosens up the scroll movement, CSS scroll snap reins it in. It adds more control over where and how the scrollport moves, forcing it to "snap" into place at positions you specify (by the way - the scrollport is just the element with the scollbar on it - whether that's the window as a whole or an element within it).

It's AMAZING - there's so much you can do with it. But that said, it's not a silver bullet. There are some use cases where it's not the ideal tool for the job, some where it can't do the job alone (and you'll need additional CSS/JS), and some cases where it's actually best avoided. Here are a few such situations...

CSS scroll snap doesn't support mouse-dragging by default

CSS scroll snap is a modification of the browser's normal scrolling behaviour - that's it. This means that you're not able - by default - to scroll through the content by clicking and dragging with your mouse.

If you scroll with the scrollbar, mousewheel, or by clicking inside the element and using the direction keys, it works just fine. However, if you try to click and drag with your mouse, you won't activate scrolling - you'll just select the text or other elements nearby as normal.

Try it below and see. For your enjoyment, I have written the content of these slides in Haiku format:

See the Pen on CodePen.

So why should you care about this? Well, a key part of usability is making your site work in the way that people expect it to work. "Don't make me think," as Steve Krug would say.

And because we're all so used to touchscreen devices these days, it's natural for people to try to replicate that type of interaction when using a normal desktop or laptop machine.

That means, if you've got a slider, you can be sure that some people will try to click and drag it. So if your slider doesn't support this, you may not be providing the optimal user experience for those users.

Scroll snap doesn't give you breadcrumbs or navigation out-of-the-box

Scroll snap is just a CSS module, it has one job - to move the scrollport to a specified position. It's not an all-singing all-dancing framework that can do multiple things.

If you're planning to do something more complex like a slider or a full page site, that's great! Just realise that scroll snap is one piece of that puzzle. If you want to add some other traditional functions like navigation buttons or breadcrumbs, you'll need to combine it with other CSS and/or JavaScript.

One cool advantage of CSS snaps is that it does something we previously had to do with JavaScript. If you can do something in CSS rather than JS, you usually should, so that visitors with JS turned off will still be able to use the site normally.

So if you wanted to make something like a slider with pure CSS, that is possible - to an extent. But you're somewhat limited in what you can do with pure CSS. In many cases you'll probably need to throw in some JS too, to get your site doing exactly what you want.

Be wary of CSS scroll snap when your content is larger than the scrollport

You might think "Ahh, wouldn't it be cool to add scroll snap to different sections of a page... maybe the headers in an article."

I like your idea - that way, people can scroll, and snap straight to the next section in the content. Wouldn't that be convenient?

Maybe not... if your sections are larger than the scrollport, your users will have trouble seeing all of your content. For example, take a setup like this:

.scrollport {
padding: 20px;
height: 500px;
overflow-y: scroll;
scroll-snap-type: y mandatory;
}

.scrollport h2 {
scroll-snap-align: start;
padding-top: 10px;
}

Here we've got a scrollport height of 500px, and we're snapping to any h2 element within the scrollport. But if the content under that h2 is longer than 500px, we'll end up with this:

See the Pen on CodePen.

If you scroll down a little to read the content, the browser will snap you to the next h2 in the scrollport element! (note that the filler text here comes from JeffSum.com. It's like Lorem Ipsum but with Jeff Goldblum quotes - and therefore much cooler).

One thing you can do here is set scroll-style-type to proximity instead of mandatory:

.scrollport {
padding: 20px;
height: 500px;
overflow-y: scroll;
scroll-snap-type: y proximity;
}

When we use mandatory, the browser will always snap to the next element when you start scrolling (like the example above). With proximity, it will only snap to an element if you are close to it, like this:

See the Pen on CodePen.

In this case, because scroll-snap-align is set to start, the browser will snap to a h2 if the top of the scrollport is close to it. Unfortunately at this time we can't control exactly how close it needs to be for it to snap - that's determined by the browser.

Creating an infinite/looping scroll can be tricky

One thing that doesn't quite work with scroll snap is an infinite, looping scroll (or should that be an infinite, scrolling loop?). This is because the elements within the scrollport are positioned alongside each other - they don't loop by default.

So what happens when you reach the last item, and then try to keep scrolling onwards?

Well, out of the box, nothing. You've reached the end of the content, and you can't scroll any further. Most sliders reach a compromise here - with some fancy CSS and a navigation buttons, you can set the slider so that a click on the forward navigation when on the last slide, will roll you back to the beginning:

See the Pen on CodePen.

This is fine, and a lot of sites do this. But you don't get that cool infinite loop effect!

So you'll need to use JavaScript for this - for example, here's how it looks in fullPage.js. Note how you can reach the third and final slide, but then keep scrolling. You end up at the first slide again, but instead of rolling back to the start - you get the impression of continuous scrolling. I don’t know about you, but I think that’s pretty cool.

Chrome issues skipping elements with css scroll snap

As for today (May 20, 2021), css scroll snapping doesn't work as one would expect when using a mouse wheel on Chrome.

Users can experience skipping of blocks when the scroll finishes and can end up annoying visitors quite a lot.

This has been reported multiple times on stackoverflow and it seems to be a Chrome bug.

Getting the right tools for the job

Don't get me wrong here - scroll snap is awesome, and brings into CSS something that we previously could only do with JS. I just wanted to tell you a little more about what it can and can't do. If you're looking to make something a little more complex, you'll need to add in a lot more CSS and probably JS to get the effect you want.

And if the thing you have in mind is a full page site that snaps nicely onto the different sections, why re-invent the wheel? Check out fullPage.js instead! Why? Well, because...

  • It resolves all of the issues discussed here - and a whole lot more
  • It'll save you time - you can take the time you would have spent coding up your own solution, and do other stuff instead
  • It's really easy to set up, and highly customisable

Basically it’s a ready-made, works out-of-the-box solution for full page sites - check it out!

About the author:

Warren is a front end developer based in the UK.
You can find more from him at https://warrendavies.net