CSS scroll-snap-stop Property
Determines if a scroll container is allowed to skip over snap positions during high-velocity scrolling.
| normal | The scroll container may skip past snap positions when the user scrolls with high momentum. |
| always | The scroll container must stop at the next snap position, even if the scroll has enough momentum to bypass it. |
Code Examples
A basic horizontal slider where every slide forces the scroll to stop, preventing the user from skipping slides even with a fast swipe.
<style>
.container {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
width: 300px;
border: 2px solid #333333;
}
.child {
flex: 0 0 100%;
height: 200px;
scroll-snap-align: center;
scroll-snap-stop: always;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
color: #ffffff;
}
.c1 { background-color: #ff5733; }
.c2 { background-color: #33ff57; }
.c3 { background-color: #3357ff; }
</style>
<div class="container">
<div class="child c1">Slide 1</div>
<div class="child c2">Slide 2</div>
<div class="child c3">Slide 3</div>
</div>An advanced vertical layout where one specific panel is set to always capture the scroll, with a JavaScript function to toggle the behavior dynamically.
<div id="scroller" style="height: 400px; overflow-y: scroll; scroll-snap-type: y mandatory; border: 2px solid #000000;">
<section class="panel" style="height: 400px; scroll-snap-align: start; scroll-snap-stop: normal; background: #e0e0e0;">Panel 1 (Skippable)</section>
<section class="panel" style="height: 400px; scroll-snap-align: start; scroll-snap-stop: normal; background: #d0d0d0;">Panel 2 (Skippable)</section>
<section id="must-stop" class="panel" style="height: 400px; scroll-snap-align: start; scroll-snap-stop: always; background: #ffcc00;">Panel 3 (Must Stop Here)</section>
<section class="panel" style="height: 400px; scroll-snap-align: start; scroll-snap-stop: normal; background: #c0c0c0;">Panel 4 (Skippable)</section>
</div>
<button onclick="toggleSnap()">Toggle Strictness</button>
<script>
function toggleSnap() {
const el = document.getElementById("must-stop");
if (el.style.scrollSnapStop === "always") {
el.style.scrollSnapStop = "normal";
el.style.backgroundColor = "#c0c0c0";
} else {
el.style.scrollSnapStop = "always";
el.style.backgroundColor = "#ffcc00";
}
}
</script>Pro Tip
You can create a "hybrid" scrolling experience by only applying "always" to specific critical items. For example, in a long horizontal list of products, you could let most items have "normal" snapping, but force an "always" stop on a "Special Offer" or "Featured Item" to ensure the user's momentum is interrupted by your most important content.
Deep Dive
When you set up a scroll snap container, users can usually flick their finger or mouse wheel to fly past multiple items at once. This is the "normal" behavior. The scroll-snap-stop property acts like a speed bump for that momentum. When set to "always" on a child element, the browser's scroll engine is forced to catch and lock into that specific element's snap point, regardless of how hard the user flicked. Think of it like a train; "normal" lets the express train blast through several small stations, while "always" forces the train to stop at the very next station no matter what. This is purely a behavioral hint to the browser to prioritize content sequence over scroll speed.
Best Practices
Use "always" when you are building interfaces where content must be viewed in a specific order, such as an image carousel, a step-by-step tutorial, or a full-page presentation. It ensures the user doesn't accidentally skip a slide. Use "normal" for standard lists or galleries where the user might want to quickly scan through many items to reach the end. Remember to apply this property to the children of the scroll container, specifically those that have scroll-snap-align defined.
Common Pitfalls
The biggest mistake is trying to apply scroll-snap-stop to the parent container. It won't do anything there. It must be applied to the child elements. Also, if you use "always" on every single child in a long list, users might find the scrolling experience frustrating because they can't move quickly through the content. It can feel like the scroll is "sticky" or broken if overused.
Accessibility
Forcing stops can be a double-edged sword. For users with limited motor control, it helps prevent over-scrolling and missing content. However, for those using specialized input devices, it might make navigation more tedious. Always ensure your scroll container allows for keyboard navigation (arrow keys, spacebar) so that the snap points are reachable for all users.
Dev Data Table: scroll-snap-stop property
| default | normal |
| animatable | no |
| inherited | no |
| experimental | no |
| year_intro | 2018 |
| year_standard | 2021 |
| js_syntax_1 | element.style.scrollSnapStop = "always"; |
| js_syntax_2 | element.style.setProperty("scroll-snap-stop", "always"); |
| js_note | This property is controlled on the child elements of a scroll container, not the container itself. |
| browsers | { "Chrome": 75, "Edge": 79, "Firefox": 68, "Safari": 15, "Opera": 62, "Chrome Android": 75, "Safari on iOS": 15, "Samsung Internet": 11, "Opera Mobile": 54 } |