CSS Scroll Snap
In this page:
.container {
scroll-snap-type: x | y mandatory | proximity;
}
.item {
scroll-snap-align: start | center | end;
}
What Is Scroll Snap?
Scroll Snap lets a scrollable container automatically settle on predefined positions as a visitor scrolls, creating the smooth, clicking-into-place feel of a native carousel or slideshow, using only CSS.
- Scroll Snap works great for horizontally scrolling tool cards or image galleries, where each item deserves its own clean, centered stop.
- Accepted values:
- scroll-snap-type — on the scroll container
- scroll-snap-align — on each child
- scroll-padding — offset for the snap area
- scroll-snap-stop — prevents skipping items
Example: What Is Scroll Snap?
<style>
.container {
overflow-x: scroll;
scroll-snap-type: x mandatory;
display: flex;
gap: 10px;
}
.item {
scroll-snap-align: center;
display: inline-block;
width: 200px;
height: 80px;
background: lightblue;
flex-shrink: 0;
}
.item:nth-child(2) {
background: lightgreen;
}
</style>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
</div>
scroll-snap-type
scroll-snap-type is set on the scrollable container itself, defining which axis (x, y, or both) participates in snapping and whether snapping is mandatory or proximity.
- Use scroll-snap-type: x mandatory for a horizontal carousel, and scroll-snap-type: y mandatory for a full-screen vertical section scroller.
- Accepted values:
- none — default, no snapping
- x | y | both — axis to snap on
- block | inline — logical axes
- mandatory — always snaps to a point
- proximity — snaps only when close
- inherit | initial | unset | revert — CSS-wide keywords accepted by every property
Example: scroll-snap-type
<style>
.container {
display: flex;
gap: 10px;
overflow-x: scroll;
scroll-snap-type: x mandatory;
background: #f0f0f0;
border: 1px solid #ccc;
padding: 10px;
}
.item {
scroll-snap-align: start;
flex-shrink: 0;
width: 200px;
height: 80px;
background: lightblue;
}
.item:nth-child(2) { background: lightgreen; }
.item:nth-child(3) { background: lightyellow; }
</style>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
scroll-snap-align
scroll-snap-align is set on the children of a snap container, marking exactly where each one should align when the browser settles on it, most commonly start, center, or end.
- center is a natural choice for a carousel where each item should feel like the visual focus once scrolling stops.
- Accepted values:
- start — snaps the item's start edge
- center — snaps the item's center
- end — snaps the item's end edge
- none — default, no snap position
- inherit | initial | unset | revert — CSS-wide keywords accepted by every property
Example: scroll-snap-align
<style>
.container {
display: flex;
gap: 10px;
overflow-x: scroll;
scroll-snap-type: x mandatory;
background: #f0f0f0;
border: 1px solid #ccc;
padding: 10px;
}
.item {
scroll-snap-align: center;
flex-shrink: 0;
width: 200px;
height: 80px;
background: lightblue;
}
.item:nth-child(2) { background: lightgreen; }
</style>
<div class="container">
<div class="item">Marks where this child aligns when scrolling stops</div>
<div class="item">2</div>
</div>
Mandatory vs Proximity Snapping
Mandatory snapping always comes to rest on a snap point after every scroll, no exceptions. Proximity snapping only snaps when the scroll happens to stop near a snap point, allowing free scrolling to rest anywhere else.
- Use proximity for long, free-scrolling content where snapping should feel like a gentle nudge, not a hard rule.
- Accepted values:
- scroll-snap-type: x mandatory — always settles on a snap point
- scroll-snap-type: x proximity — snaps only when near a point
- mandatory — can trap users with tall items
- proximity — gentler, browser decides
Example: Mandatory vs Proximity Snapping
<style>
.row {
display: flex;
gap: 10px;
overflow-x: scroll;
padding: 10px;
margin-bottom: 12px;
background: #f0f0f0;
border: 1px solid #ccc;
}
.mandatory { scroll-snap-type: x mandatory; }
.proximity { scroll-snap-type: x proximity; }
.item {
scroll-snap-align: center;
flex-shrink: 0;
width: 200px;
height: 80px;
background: lightblue;
}
.item:nth-child(2) { background: lightgreen; }
</style>
<div class="row mandatory">
<div class="item">Always comes to rest on a snap point</div>
<div class="item">2</div>
</div>
<div class="row proximity">
<div class="item">Only snaps if it stops near one</div>
<div class="item">2</div>
</div>
scroll-padding and scroll-snap-stop
scroll-padding offsets the snap area, useful when a sticky header would otherwise cover the top of a snapped section. scroll-snap-stop: always forces the browser to stop at every snap point in sequence, instead of skipping past several during a fast scroll or swipe.
- Set scroll-padding-top to match a sticky header's height so snapped content never ends up hidden underneath it.
- Accepted values:
- scroll-padding: <length> — offsets the scroll port edge
- scroll-snap-stop: normal — default, may skip snap points
- scroll-snap-stop: always — must stop at each snap point
- scroll-padding-top — per-side variants exist
Example: scroll-padding and scroll-snap-stop
<style>
.container {
display: flex;
gap: 10px;
overflow-x: scroll;
scroll-snap-type: x mandatory;
scroll-padding-left: 60px;
background: #f0f0f0;
border: 1px solid #ccc;
padding: 10px;
}
.item {
scroll-snap-align: start;
scroll-snap-stop: always;
flex-shrink: 0;
width: 200px;
height: 80px;
background: lightblue;
}
.item:nth-child(2) { background: lightgreen; }
.item:nth-child(3) { background: lightyellow; }
</style>
<div class="container">
<div class="item">Offsets past a sticky header, stops at every item</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
- Setting scroll-snap-type on the container but forgetting scroll-snap-align on its children, resulting in no visible snapping at all.
- Using mandatory snapping on a container with only one or two children, which can make scrolling feel oddly restrictive.
- Forgetting overflow: auto (or scroll) on the snap container, without it there's nothing to actually scroll and snap within.
- scroll-snap-type turns a scrollable container into a snap container, along an x, y, or both axis.
- scroll-snap-align marks where each child should snap to, most commonly start or center.
- Mandatory snapping always settles on a snap point, while proximity snapping only does so when scrolling stops near one.
CSS Scroll Snap properties are supported by all modern browsers.
Chapter Quiz — Complete all 22 topics to unlock
0/22 topics done
Complete these topics first:
- CSS Gradients
- CSS Shadows
- CSS Filters
- CSS Blend Modes
- CSS Transforms
- CSS 2D Transforms
- CSS 3D Transforms
- CSS Transitions
- CSS Animations
- CSS Image Styling
- CSS Image Effects
- CSS Hover Overlays
- CSS Image Modal
- CSS Image Centering
- CSS Image Shapes
- CSS Buttons
- CSS Columns
- CSS Clip Path
- CSS Shapes
- CSS Scroll Snap
- CSS Architecture: BEM
- CSS Custom Properties