ESC

Type to search the knowledge base.

Overflow Scroll and Scroll Snap

overflow, scroll containers, and scroll-snap for carousels and section snaps — touch behavior, accessibility, and nested scroll traps.

intermediate3 min read
  • css
  • overflow
  • scroll-snap

Overflow controls what happens when content exceeds a box. Scroll containers power chat panes, tables, and carousels. Scroll snap aligns scroll positions to items so users land cleanly on cards or full-viewport sections — without reinventing touch math in JavaScript.

Docs: MDN overflow, scroll snap.

overflow basics

.panel {
  max-height: 20rem;
  overflow: auto; /* scrollbars only if needed */
}

.clip {
  overflow: hidden; /* crop; no scroll */
}

.scroll-x {
  overflow-x: auto;
  overflow-y: hidden;
}
Value Behavior
visible Default; paint outside box
hidden Clip
clip Clip without programmatic scroll (stricter)
scroll Always show scrollport (scrollbar gutter depends on OS/UA)
auto Scrollports when overflowing

overflow other than visible can create a scroll container and a block formatting / containing block side effects (e.g. sticky descendants, margin collapse).

Making nested flex/grid areas scroll

.shell {
  display: flex;
  flex-direction: column;
  height: 100dvh;
}

.shell__body {
  flex: 1;
  min-height: 0; /* critical */
  overflow: auto;
}

Without min-height: 0 (or min-width: 0 in a row), the flex item won’t shrink below content size and the page scrolls instead of the pane.

<ul class="scroller">
  <li class="scroller__item">1</li>
  <li class="scroller__item">2</li>
  <li class="scroller__item">3</li>
</ul>
.scroller {
  display: flex;
  gap: 1rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: 1rem;
  padding-inline: 1rem;
  list-style: none;
  margin: 0;
  -webkit-overflow-scrolling: touch;
}

.scroller__item {
  flex: 0 0 80%;
  scroll-snap-align: start;
  scroll-snap-stop: always; /* optional: force stop per item */
}
Property Role
scroll-snap-type On container: axis + mandatory/proximity
scroll-snap-align On items: start/center/end
scroll-padding Insets for fixed headers / peek gutters
scroll-margin Item-side offset

proximity snaps when close; mandatory insists on a snap point (can feel aggressive — test).

Full-page section snap

.story {
  height: 100dvh;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
}

.story__panel {
  height: 100dvh;
  scroll-snap-align: start;
}

Marketing sites love this; power users and accessibility advocates often don’t. Provide a way to scroll freely and respect reduced motion (avoid hijacking).

Accessibility

  • Keyboard: ensure focusable items inside scrollers are reachable; don’t trap focus.
  • Prefer real buttons for prev/next that scrollBy/scrollTo with behavior: 'smooth' only if motion allows.
  • Announce carousel state if it’s a composite widget (APG patterns).
  • Don’t rely on snap alone for essential content discovery.
@media (prefers-reduced-motion: reduce) {
  .scroller {
    scroll-behavior: auto;
  }
}

Interview out-loud

“overflow: auto creates a scrollport when content overflows. Nested scroll in flex layouts needs min-height: 0. Scroll snap uses scroll-snap-type on the container and scroll-snap-align on children for carousels or sections. I pick proximity vs mandatory carefully and keep keyboard and reduced-motion in mind.”

Footguns

  1. Nested scroll traps (page + pane both competing).
  2. mandatory snap fighting user intent.
  3. Sticky headers covering snap starts — use scroll-padding.
  4. Hiding scrollbars without alternate affordances.
  5. Forgetting RTL: horizontal scrollers need logical testing.

Further reading

Related guides