CSS Scroll Snap

CSS scroll snap controls where a scroll container comes to rest after a user scrolls. It allows selected child elements to align with defined snap positions, making it useful for image galleries, card rows, slides, and other scrollable interfaces.

Scroll snapping is primarily controlled by properties on the scroll container and its children. The container defines the snapping behavior, while the child elements define their individual snap positions.

How Scroll Snap Works

Scroll snapping requires a scroll container and one or more descendants that define snap positions.

.gallery {
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}
.item {
  scroll-snap-align: start;
}

The .gallery element scrolls horizontally and establishes a horizontal snap container. Each .item provides a snap position aligned with its start edge.

When scrolling finishes, the browser can adjust the final scroll position so an appropriate item aligns with the container's snap area.

Creating a Scroll Container

Scroll snapping operates on a scroll container. An element becomes scrollable when its content exceeds its available size and an appropriate overflow value allows scrolling.

.gallery {
  display: flex;
  overflow-x: auto;
}

If the child elements extend beyond the gallery's inline size, the user can scroll horizontally through them.

Adding scroll-snap-type defines how that scrolling interacts with snap positions.

.gallery {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}

The scroll-snap-type Property

The scroll-snap-type property is applied to the scroll container. It specifies the snap axis and how strictly snapping should occur.

.gallery {
  scroll-snap-type: x mandatory;
}

The first value identifies the axis. The second value specifies the strictness of the snapping behavior.

Value Description
none Disables scroll snapping.
x Uses snap positions along the horizontal axis.
y Uses snap positions along the vertical axis.
block Uses snap positions along the block axis.
inline Uses snap positions along the inline axis.
both Uses snap positions along both axes.

Choosing the Snap Axis

The snap axis should match the direction in which the content is intended to scroll.

.horizontal {
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}
.vertical {
  overflow-y: auto;
  scroll-snap-type: y mandatory;
}

The physical x and y values correspond to horizontal and vertical axes.

The logical inline and block values follow the writing mode, which can make them useful when a layout needs to adapt to different writing systems.

mandatory and proximity

The strictness value determines how strongly the scroll container follows its snap positions.

.gallery {
  scroll-snap-type: x mandatory;
}

With mandatory, the browser must snap to a snap position when one exists after scrolling completes.

.gallery {
  scroll-snap-type: x proximity;
}

With proximity, the browser may snap when the scrolling position is sufficiently close to a snap position. The exact snapping behavior is determined by the browser.

proximity can provide a less restrictive experience when users should be able to stop more freely between snap positions.

The scroll-snap-align Property

The scroll-snap-align property is applied to descendants of the scroll container. It specifies how an element's snap area aligns with the scroll container's snapport.

.item {
  scroll-snap-align: start;
}

Common values include:

Value Description
none The element does not define a snap position on that axis.
start Aligns the start of the element's snap area with the snapport.
center Aligns the center of the element's snap area with the snapport.
end Aligns the end of the element's snap area with the snapport.
.item {
  scroll-snap-align: center;
}

This can be useful for a gallery where each item should settle in the center of the visible scrolling area.

The scroll-snap-stop Property

The scroll-snap-stop property controls whether a scroll operation can pass over an element's snap position.

.item {
  scroll-snap-stop: normal;
}

The default normal value allows the scrolling operation to pass over possible snap positions.

.important-item {
  scroll-snap-stop: always;
}

The always value prevents a scrolling operation from passing over that snap position when it would otherwise do so.

This can be useful when a particular snap position should not be skipped during a scrolling operation, but it should be used only when that stricter behavior improves the interface.

Scroll Padding

The scroll-padding properties define offsets inside the scroll container's optimal viewing region. This can keep snapped content away from an edge or account for content that visually occupies part of the scrolling area.

.gallery {
  scroll-snap-type: x mandatory;
  scroll-padding-inline: 20px;
}

The inline scroll padding creates space at the inline edges of the snapport when snap positions are calculated.

Physical and logical scroll-padding properties are available, including scroll-padding-top, scroll-padding-inline, and scroll-padding-block.

Scroll Margin

The scroll-margin properties add an outset around an element's scroll snap area.

.item {
  scroll-snap-align: start;
  scroll-margin-inline: 10px;
}

This changes the area used when the browser determines the element's snap position.

Scroll margin belongs to the element being snapped, while scroll padding belongs to the scroll container.

Horizontal Scroll Snap

Horizontal snapping is commonly used for card rows and galleries.

.gallery {
  display: flex;
  gap: 20px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}
.card {
  flex: 0 0 80%;
  scroll-snap-align: start;
}

The cards remain in a horizontal row and the container can scroll along the x-axis. Each card provides a start-aligned snap position.

The card width can be adjusted to show one complete item or part of the next item depending on the desired design.

Vertical Scroll Snap

Vertical snapping uses the same basic approach but creates scrolling along the y-axis.

.sections {
  height: 400px;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
}
.section {
  min-height: 400px;
  scroll-snap-align: start;
}

As the user scrolls vertically, each section can settle at the defined snap position.

Strong mandatory snapping should be used carefully when content varies in size. Users should still be able to reach and read all of the content inside the scrolling area.

Scroll Snap Practices

Practice Purpose
Match the snap axis to the scroll direction Keeps snapping consistent with the way users move through the content.
Choose mandatory or proximity carefully Provides an appropriate balance between strict snapping and free scrolling.
Use clear snap positions Makes the final position of each item predictable.
Use scroll padding when needed Provides space between snapped content and the edges of the snapport.
Avoid trapping content Ensures users can reach all content, especially when items are larger than the scrolling area.
Test different input methods Checks scrolling behavior with touch, trackpads, mouse wheels, and keyboards where applicable.

CSS Scroll Snap Example

The following example creates a horizontal row of cards that snap to the start of the scrolling area.

.gallery {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}
.card {
  flex: 0 0 80%;
  scroll-snap-align: start;
}

Scroll horizontally through the example to see each card snap into position. Open the example in the editor and change mandatory to proximity, or change scroll-snap-align: start to center, to compare the scrolling behavior.

Play in Editor