![]() |
VOOZH | about |
The idea of only needing CSS to customize your scroll instead of playing with JavaScript sounds great, doesn’t it?
👁 An image illustrating CSS scroll snap.Today, I’m going to show you how CSS Scroll Snap helps you do just that.
The Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
I bet you’ve used some libraries to control the scrolling behavior of your website. I have, and I had a terrible time with some of them.
Some of these libraries can drag your page’s performance and user experience way down.
Not to mention that it’s a real pain to deal with all the bugs they sometimes generate as you add more complexity with your new design updates.
That’s why I prefer to use this simple CSS feature that allows me to get a beautiful scroll through my page without having to rely on JavaScript libraries.
These properties also help me save a ton of time.
In simple terms, CSS Scroll Snap makes the scroll snap, locking the viewport at a specific point (that you indicate) with each scroll.
A linear scroll, on the other hand, moves according to the rate of the controller — whether that be a mouse, touch gesture, or arrow keys.
Now, let’s see how CSS Scroll Snap works.
If you want to go straight to a real-life example, head over to the third section where I’ve built the Instagram carousel with a few lines of CSS code.
Let’s get started.
CSS Scroll Snap works by applying two primary properties: scroll-snap-type and scroll-snap-align.
Here is what you need to know about each:
scroll-snap-type, is applied to the parent container. It accepts two arguments: the snap direction and the snap behavior:.container {
scroll-snap-type: [ x | y | block | inline | both ] [ mandatory | proximity ];
}
About the snap behavior arguments: choosing proximity makes the snap only appear at the nearest point to where the user stopped scrolling.
On the other hand, mandatory makes the snap happen at the specific position you choose when the user is scrolling.
scroll-snap-align, is applied to the container’s children.This is where you specify the snap point for the x-axis and the y-axis:
.children {
scroll-snap-align: [ none | start | end | center ]{1,2};
}
Before we continue, it’s important to note that none of this is going to work unless you specify the container’s overflow and give it a fixed height.
Additionally, you should never use mandatory if the content inside one of your child elements is longer than the parent container. If you do, the user won’t be able to see that content.
There are two more properties we need to familiarize ourselves with:
scroll-padding (applied to the parent container) is pretty much like the CSS padding property and acts as the offset. You also have scroll-padding-top, scroll-padding-bottom, scroll-padding-left and scroll-padding-right.scroll-margin (applied to the container’s children) is also like the CSS margin property and serves as the outset. You also have scroll-margin-top, scroll-margin-bottom, scroll-margin-left and scroll-margin-right.If you are interested in learning more about all scroll snap properties and future ones, the Mozilla documentation is always a good place to start.
To help you get a better grasp on this concept, I made a little Instagram-like carousel on codepen.
See the live demo here:
CSS Scroll Snap – Instagram-like Carousel
No Description
As you can see, it includes seven boxes with different sizes.
What amazes me is that we don’t have anything else to do other than add the CSS lines below to automatically make the scroll snap to each box.
<style>
.container {
width: 60vw;
height: 70vh;
margin: 15vh auto;
overflow-x: scroll;
scroll-snap-type: x mandatory;
color: white;
background-color: oldlace;
display: flex;
align-items: center;
}
.child {
margin-left: 0.5rem;
height: 90%;
scroll-snap-align: start;
padding: 1rem;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.child:nth-child(1n) {
background-color: darkorchid;
flex: 0 0 80%;
}
.child:nth-child(2n) {
background-color: indigo;
flex: 0 0 60%;
}
.child:nth-child(3n) {
background-color: navy;
flex: 0 0 40%;
}
.child:nth-child(4n) {
background-color: palegreen;
flex: 0 0 50%;
}
.child:nth-child(5n) {
background-color: yellow;
flex: 0 0 80%;
}
.child:nth-child(6n) {
background-color: orange;
flex: 0 0 60%;
}
.child:nth-child(7n) {
background-color: tomato;
flex: 0 0 80%;
}
</style>
Solving this issue with only JavaScript would have required a lot of extra work.
Okay, now let’s get to the million-dollar question: cross-browser support.
As you can see here, the CSS Scroll Snap functionality is well supported across modern browsers.
The only issue you’ll encounter is with Internet Explorer, which requires an older version of the specs that you can find here.
Also, I would advise you to add the property -webkit-overflow-scrolling: touch; to your container to support iOS devices.
That’s pretty much it!
It’s so simple, but there were times where this could have saved me hours of code. Try to implement a scroll snap using JavaScript and recalculate the snap point with each child element with different widths, and you’ll see what I mean.
If you have any questions or remarks, please feel free to let me know in the comments or to ping me on Twitter @RifkiNada. I always reply.
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
👁 LogRocket Dashboard Free Trial BannerLogRocket lets you replay user sessions, eliminating guesswork around why bugs happen by showing exactly what users experienced. It captures console logs, errors, network requests, and pixel-perfect DOM recordings — compatible with all frameworks.
LogRocket's Galileo AI watches sessions for you, instantly identifying and explaining user struggles with automated monitoring of your entire product experience.
Modernize how you debug web and mobile apps — start monitoring for free.
TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension — no new framework required.
Learn how to build a full React Native auth system using Better Auth and Expo — with email/password login, Google OAuth, session persistence, and protected routes.
Compare the top AI development tools and models of June 2026. View updated rankings, feature breakdowns, and find the best fit for you.
Learn how Bloom filters reduce database lookups for username availability checks while preserving correctness at scale.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now