Expert9 min read

CSS Scroll Snap: Creating Smooth Scrolling Experiences

9 min read
305 words
16 sections13 code blocks

What is CSS Scroll Snap?

CSS Scroll Snap gives you control over the scroll position after a user finishes scrolling. Instead of landing at an arbitrary position, the scroll will snap to specific points you define. This creates smooth, precise scrolling experiences without JavaScript.

Basic Scroll Snap Setup

Scroll snap requires two things:

  1. A scroll container with snap rules
  2. Snap targets (child elements) that define snap points
CSS
/* The scroll container */
.container {
  scroll-snap-type: y mandatory;
  overflow-y: scroll;
  height: 100vh;
}

/* The snap targets */
.section {
  scroll-snap-align: start;
  height: 100vh;
}

scroll-snap-type

Defines the snap direction and strictness on the scroll container:

CSS
/* Vertical snapping */
.container { scroll-snap-type: y mandatory; }

/* Horizontal snapping */
.container { scroll-snap-type: x mandatory; }

/* Both directions */
.container { scroll-snap-type: both mandatory; }

mandatory vs proximity

CSS
/* mandatory: ALWAYS snaps to a snap point after scrolling */
scroll-snap-type: y mandatory;

/* proximity: Only snaps when close to a snap point */
scroll-snap-type: y proximity;
  • mandatory: Use when every section must be fully visible (full-page scroll)
  • proximity: Use for a gentler snap that only activates when near a target (image galleries)

scroll-snap-align

Defines which part of the child element aligns with the scroll container:

CSS
.item { scroll-snap-align: start; }   /* Top/left of item aligns */
.item { scroll-snap-align: center; }  /* Center of item aligns */
.item { scroll-snap-align: end; }     /* Bottom/right of item aligns */

Practical Examples

Full-Page Scroll Sections

CSS
.page-container {
  scroll-snap-type: y mandatory;
  overflow-y: scroll;
  height: 100vh;
}

.page-section {
  scroll-snap-align: start;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.page-section:nth-child(1) { background: #3498db; }
.page-section:nth-child(2) { background: #2ecc71; }
.page-section:nth-child(3) { background: #e74c3c; }
.page-section:nth-child(4) { background: #f39c12; }
CSS
.gallery {
  display: flex;
  overflow-x: scroll;
  scroll-snap-type: x mandatory;
  gap: 1rem;
  padding: 1rem;
  -webkit-overflow-scrolling: touch;
}

.gallery__item {
  scroll-snap-align: center;
  flex: 0 0 80%;
  border-radius: 12px;
  overflow: hidden;
}

.gallery__item img {
  width: 100%;
  height: 300px;
  object-fit: cover;
}
CSS
.carousel {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  gap: 1.5rem;
  padding: 1rem;
  scroll-padding: 1rem;
}

.carousel::-webkit-scrollbar {
  display: none;
}

.carousel__card {
  scroll-snap-align: start;
  flex: 0 0 300px;
  background: white;
  border-radius: 12px;
  padding: 1.5rem;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

scroll-padding

Adds an offset so items don't snap directly to the edge. Useful when you have a fixed header:

CSS
.container {
  scroll-snap-type: y mandatory;
  overflow-y: scroll;
  scroll-padding-top: 80px; /* Account for fixed header */
}
CSS
/* All sides */
scroll-padding: 1rem;

/* Individual sides */
scroll-padding-top: 80px;
scroll-padding-inline: 1rem;

scroll-margin

Adds an offset on the snap target side (the child):

CSS
.section {
  scroll-snap-align: start;
  scroll-margin-top: 80px; /* Offset from top when snapping */
}

scroll-snap-stop

Controls whether a fast scroll can skip snap points:

CSS
/* normal: fast scrolling can skip past snap points (default) */
.item { scroll-snap-stop: normal; }

/* always: must stop at every snap point */
.item { scroll-snap-stop: always; }

Use always for important content that should never be skipped.

Hiding Scrollbar

For a cleaner look, you can hide the scrollbar while keeping scroll functionality:

CSS
.carousel {
  overflow-x: auto;
  scrollbar-width: none; /* Firefox */
}

.carousel::-webkit-scrollbar {
  display: none; /* Chrome, Safari */
}

Vertical Snap with Variable Heights

CSS
.scroll-container {
  scroll-snap-type: y proximity;
  overflow-y: scroll;
  height: 100vh;
}

.content-section {
  scroll-snap-align: start;
  min-height: 50vh;
  padding: 3rem 2rem;
}

Using proximity instead of mandatory works better when sections have variable heights.

Accessibility Considerations

  • Always ensure users can still scroll freely with keyboard and assistive devices
  • Use proximity over mandatory when sections have varying content lengths
  • Add scroll-padding to account for fixed navigation
  • Test with keyboard navigation (Tab, arrow keys)

Summary

CSS Scroll Snap creates polished scrolling experiences purely with CSS. Use scroll-snap-type on the container for direction and strictness, scroll-snap-align on children for alignment, scroll-padding for fixed header offsets, and scroll-snap-stop: always for must-see content. It is perfect for full-page scrolling, image carousels, card galleries, and any horizontal or vertical scroll-based navigation.