What CSS Scroll Snap does
Scroll Snap lets a scroll container rest on defined snap points instead of stopping anywhere. It powers carousels, paginated galleries and full-screen sections with no JavaScript. The properties split cleanly: a few go on the scroll container to define the axis and strictness, and the rest go on each scrollable item to define where it aligns. This reference lists them all with their accepted values.
How it works
The container declares an axis and strictness with scroll-snap-type; each
child declares where it rests with scroll-snap-align:
.carousel {
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-padding-left: 1rem;
}
.carousel > .slide {
scroll-snap-align: start;
scroll-snap-stop: always;
scroll-margin-left: 0.5rem;
}
mandatory guarantees the scroll always lands on a slide; proximity only
snaps when you release near one. scroll-snap-align: start aligns each slide’s
left edge to the (padded) container edge. scroll-snap-stop: always blocks a
single fling from skipping past slides.
Complete carousel recipe
A full-page horizontal carousel with centered snapping and a sticky header clearance:
/* Scroll container */
.carousel {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-padding-inline-start: 1rem; /* clears any inset from the container edge */
-webkit-overflow-scrolling: touch; /* momentum on iOS */
}
/* Each slide */
.slide {
flex: 0 0 100%; /* full-width slide */
scroll-snap-align: start;
scroll-snap-stop: always; /* no swipe-skipping */
}
For centred cards where you want partial peek of adjacent cards:
.carousel { scroll-padding-inline: 10%; }
.card {
flex: 0 0 80%;
scroll-snap-align: center;
}
The 10% padding insets the snap boundary so the card centers with 10% of adjacent cards peeking in from each side.
Clearing a sticky header with scroll-padding
If your page has a fixed header (for example, 60 px tall), scroll targets can snap
underneath it. scroll-padding-block-start insets the container’s snap area
so items stop below the header:
.page {
overflow-y: auto;
scroll-snap-type: y proximity;
scroll-padding-block-start: 60px;
}
.section {
scroll-snap-align: start;
}
scroll-margin on an individual item achieves the same offset for that item
only, without affecting all snapping.
mandatory vs proximity
mandatory is the stricter mode: the user cannot release the scroll between
snap points — it always jumps to the nearest. This works well for full-screen
sections or single-item carousels where landing between items would leave a
broken-looking partial view.
proximity only snaps when the user releases near a snap point. Scrolling
quickly past several items works normally, and the scroll only locks when the
user slows and stops near a boundary. Prefer proximity for long scrollable
lists where free scrolling is more important than precision.
Tips and notes
- A snap container must actually scroll — set
overflowand a constrained size, or nothing snaps. - Combine
scroll-padding(container) withscroll-margin(item) to clear a sticky header. - Use logical-axis values
block/inlinefor writing-mode-aware snapping. scroll-snap-align: noneopts a single item out of snapping inside a snapping container.mandatoryon a long page where items are taller than the viewport can trap users —proximityis safer in that case.