⚡IntermediateModern CSS

CSS Scroll Snap

Create controlled, polished scrolling experiences that snap to specific positions using scroll-snap-type and scroll-snap-align.

Overview

CSS Scroll Snap creates controlled scrolling where items "snap" to predetermined positions as the user scrolls, providing a polished carousel or full-page scroll experience without JavaScript. Two parties involved: 1. **Scroll container** (parent) set `scroll-snap-type` 2. **Snap targets** (children) set `scroll-snap-align` Key properties: - `scroll-snap-type: x mandatory` horizontal snapping, always snaps - `scroll-snap-type: y proximity` vertical, snaps only when close - `scroll-snap-align: start | center | end` which edge of the child aligns to the container - `scroll-snap-stop: always` prevents fast scrolling from skipping items - `scroll-padding` offsets the snap point (useful when there's a sticky header) - `scroll-margin` adds margin around snap targets

Key Points

  • •scroll-snap-type goes on the scroll container (overflow: scroll/auto required)
  • •mandatory always snaps to the nearest snap point; proximity snaps only when close
  • •scroll-snap-align: center is best for carousels (child centers in viewport)
  • •scroll-snap-align: start is best for full-page sections
  • •scroll-padding-top on the container offsets snap for sticky headers
  • •scroll-snap-stop: always prevents users from skipping items in mandatory mode
  • •Use scroll-behavior: smooth on html for smooth keyboard scrolling

Examples

Horizontal card carousel with snap

.carousel {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  gap: 16px;
  padding: 16px;
  scrollbar-width: none; /* hide scrollbar in Firefox */
}
.carousel::-webkit-scrollbar { display: none; } /* Chrome/Safari */

.carousel-item {
  flex: 0 0 80%;      /* item takes 80% of container width */
  scroll-snap-align: center;
  border-radius: 16px;
}

flex: 0 0 80% prevents the item from growing or shrinking. Combining with scroll-snap-align: center creates a peek-at-next-card effect.

Full-page vertical scroll sections

.full-page-scroll {
  height: 100dvh;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
}

.page-section {
  height: 100dvh;           /* each section fills the viewport */
  scroll-snap-align: start;  /* top edge snaps to container top */
  display: flex;
  align-items: center;
  justify-content: center;
}

Scroll padding for sticky header offset

/* Sticky header is 64px tall */
.scroll-container {
  scroll-snap-type: y mandatory;
  scroll-padding-top: 64px; /* offset snap by header height */
  overflow-y: auto;
  height: 100dvh;
}

.section {
  scroll-snap-align: start;
  padding-top: 64px; /* space for header */
}

Without scroll-padding, content would snap behind the sticky header.

Common Mistakes

  • Forgetting overflow on the scroll container scroll-snap-type has no effect without overflow: scroll or overflow: auto
  • Using scroll-snap-type on the whole page body without height the body needs a defined height to scroll
  • Setting mandatory without ensuring items are large enough if gaps exceed the container, the browser may not find a valid snap point

Note

Add scrollbar-width: none (Firefox) and .container::-webkit-scrollbar { display: none } (Chrome) to create a clean touch-like carousel. Users can still scroll by swiping or dragging.

Exercises

Write CSS to style the HTML scaffold. The preview updates live — when it looks right, mark as done.

Loading editor…

Completed: 0 / 5 exercises

Knowledge Check

Question 1 of 4

Where do you place the scroll-snap-type property?