CSS Scroll Snap allows you to control scroll behavior by defining snap points — positions where the scrollport locks into place. This creates polished, app-like scrolling experiences for carousels, image galleries, section-by-section pages, and horizontal timelines.
Scroll Snap is entirely CSS-driven, requiring no JavaScript for the snap logic. It works on both horizontal and vertical scroll containers and provides fine-grained control over snap alignment and stopping behavior.
scroll-snap-basics.css
CSS
1
.scroll-container {
2
scroll-snap-type: x mandatory;
3
overflow-x: auto;
4
display: flex;
5
gap: 16px;
6
}
7
8
.scroll-item {
9
scroll-snap-align: start;
10
flex: 0 0300px;
11
}
scroll-snap-type
The scroll-snap-type property is set on the scroll container. It defines the axis and snap strictness: whether snapping is required (mandatory) or suggested (proximity).
scroll-snap-type.css
CSS
1
.container {
2
/* Axis */
3
scroll-snap-type: none; /* default — no snapping */
scroll-snap-type: x mandatory; /* must snap to the nearest point */
12
scroll-snap-type: y proximity; /* snaps only when close enough */
13
scroll-snap-type: both mandatory;
14
}
⚠
warning
Use mandatory carefully — if content is larger than the viewport, the user may become stuck unable to scroll past certain items. Reserve mandatory for cases where each snap item fits within the scrollport.
scroll-snap-align
Set on child elements, scroll-snap-align defines where the element snaps to within the scroll container — at its start, center, or end.
scroll-snap-align.css
CSS
1
.item {
2
scroll-snap-align: start; /* snaps to the start of the container */
3
scroll-snap-align: center; /* centers in the container */
4
scroll-snap-align: end; /* snaps to the end of the container */
5
scroll-snap-align: none; /* excluded from snapping */
6
}
7
8
/* Different items can have different alignment */
Controls whether the scroll container is allowed to pass over snap positions during a fast scroll gesture. By default (normal), fast scrolls can skip items. Setting always forces the scroll to stop at every snap position.
scroll-snap-stop.css
CSS
1
.item {
2
scroll-snap-stop: normal;/* default — can skip during fast scrolls */
3
scroll-snap-stop: always;/* force stop at this snap position */
4
}
ℹ
info
Use scroll-snap-stop: always for section-by-section page layouts where skipping content would be disorienting. For carousels and galleries, normal provides a better user experience.
scroll-margin
scroll-margin adds space around a snap target, pushing the snap position inward. This is useful for creating visual breathing room or accounting for fixed headers.
scroll-margin.css
CSS
1
.item {
2
scroll-snap-align: start;
3
scroll-margin: 20px; /* 20px inset on all sides */
4
scroll-margin-top: 60px;/* account for fixed header */
scroll-padding is set on the scroll container and defines the offset that snap positions must respect. This is ideal for ensuring content is visible past fixed headers or toolbars.
scroll-padding.css
CSS
1
.scroll-container {
2
scroll-snap-type: y mandatory;
3
scroll-padding-top: 80px;/* snap starts 80px below top */
/* With sticky header — content snaps below the header */
9
.header {
10
position: sticky;
11
top: 0;
12
height: 60px;
13
}
14
15
.main {
16
scroll-snap-type: y mandatory;
17
scroll-padding-top: 60px;
18
}
19
20
.section {
21
scroll-snap-align: start;
22
min-height: 100vh;
23
}
Horizontal & Vertical Snap
Scroll Snap works on both axes. The patterns differ slightly based on the layout direction.
Horizontal Snap (Carousel)
horizontal-snap.css
CSS
1
.carousel {
2
display: flex;
3
overflow-x: auto;
4
scroll-snap-type: x mandatory;
5
gap: 16px;
6
scroll-padding: 024px;
7
}
8
9
.carousel-item {
10
flex: 0 0 80%;
11
scroll-snap-align: start;
12
max-width: 400px;
13
}
Vertical Snap (Full Page)
vertical-snap.css
CSS
1
.fullpage {
2
height: 100vh;
3
overflow-y: auto;
4
scroll-snap-type: y mandatory;
5
scroll-snap-stop: always;
6
}
7
8
.fullpage-section {
9
height: 100vh;
10
scroll-snap-align: start;
11
display: flex;
12
align-items: center;
13
justify-content: center;
14
}
preview
Mandatory vs Proximity
The strictness value determines how aggressively the scrollport snaps to positions.
Value
Behavior
Best For
mandatory
Always snaps to the nearest snap position when scrolling stops
Carousels, galleries, step-by-step wizards
proximity
Only snaps if the scroll position is close enough to a snap point
Long pages, scrolling lists, content that needs free scrolling
📝
note
Proximity is the safer choice for unknown content sizes. Mandatory can trap users if an item is larger than the scrollport — the browser cannot snap away from it.