Why not to use CSS scroll snap

Warren Davies Avatar

Follow on Twitter

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…

Your scroll-based animations might stop working

If you are using third-party libraries to generate animations based on the scroll position, these might stop working. This also applies to CMSs or website builders, such as Webflow, Elementor, Wix, etc.

It all depends on how you implement CSS scroll snaps and what are your restrictions.

The root of the problem is that, when using a CSS Snaps in full-screen and applying it on any element that is not the html element, the scrolled position is no longer available in any of the following properties (as most scroll-based libraries expect):

  • document.documentElement.scrollTop
  • window.pageYOffset
  • document.documentElement.clientTop

Instead, the value of the scroll position will now be on document.body.scrollTop.

This is because the scrolling element is no longer the window or documentElement, but the container you chose for the snap scroll. It can be the body itself or any other wrapper around your sections.

On top of that, the event listener on the window object won’t catch the scroll event anymore:

/*
* Not capturing the event when CSS snaps is 
* applied on a container.
*/
window.addEventListener('scroll', onScroll);

/* 
* Capturing the event when CSS snaps is 
* applied on the body.
*/
document.body.addEventListener('scroll', onScroll);

/*
* Capturing the event when CSS snaps is
* applied on a wrapper.
*/
document.querySelector('.my-wrapper')
  .addEventListener('scroll', onScroll);
Code language: JavaScript (javascript)

This can be a bit tricky and might generate unexpected conflicts with external libraries, website builders or even with your own code.

Here’s a codepen illustrating the issue. Notice you won’t get any message on the JS console:

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:

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.

Problems using 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;
}
Code language: CSS (css)

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:

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;
}
Code language: CSS (css)

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:

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.

Snap to non full-screen sections will cause issues

CSS scroll snap can do the trick when working with full-screen sections. However, when you want to work with non-fullscreen sections you will find some obvious problems.

You might not be able to snap to the section you want and you’ll feel like you’ve lost control over the page scrolling.

Here I demonstrate how I want to snap to section 2 when scrolling down and it goes back to section 1 unless section 2 is above the middle of the screen.

Also, when I place myself in section 3, it’s literally impossible to snap to section 2.

You can test it yourself in the following Codepen:

Creating an infinite/looping scroll will 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:

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, 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.

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.

Scroll Snap Is Just Not a Complete Library

It’s like comparing Apples to Oranges.

fullPage.js is a JavaScript library that comes with a huge range of configurable options, methods, and callbacks.

Scroll Snaps is a single CSS feature to achieve a very specific scrolling behavior.

They have one single thing in common. They provide a similar scrolling effect. Apart from that, Scroll Snaps doesn’t provide any other additional features, while fullPage.js provide a ton.

A quick look at the fullpage.js documentation is enough to know fullPage.js is way more than a scrolling effect.

So, what does this mean to you as a web developer?

It means that fullPage.js comes with a set of tools that can save you a lot of time while developing a page. Things like navigation bullets, enable/disable scroll based on whatever conditions you need, responsive options, control over keyboard scrolling, the trigger of actions on different states of the movement, scrollable sections, etc.

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 A LOT of 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.
  • It provides tens of features that you will soon start missing if you start making a site with CSS scroll snaps. (Callbacks, CSS state classes, responsive options, URL hash, methods, scrollable sections etc.)

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

Was this page helpful?