Home/Learn/HTML, CSS & Responsive/Overflow and Scrolling

Overflow and Scrolling

Intermediate
Layout

Content that does not fit has to go somewhere. Choosing deliberately — clip, scroll, wrap or truncate — and making the result keyboard-accessible is the difference between a bug and a feature.

Overview

Overflow is where layout meets real content, which is always longer than the design assumed. The default is to spill visibly, which at least makes the problem obvious; overflow: hidden makes it invisible, which is why content silently disappears in production. Beyond the property itself, this concept covers the horizontal-scrollbar hunt every developer eventually runs, scroll snapping, and the accessibility rule that a scrollable region must be reachable by keyboard.

The Values, and Their Side Effects

Each does more than clip.

auto vs hidden vs clip
overflow: visible   /* default — content spills, visibly */
overflow: hidden    /* clipped, NOT scrollable — even by keyboard */
overflow: scroll    /* always shows a scrollbar track */
overflow: auto      /* scrollbar only when needed — usually correct */
overflow: clip      /* clips without creating a scroll container */

/* Separate axes */
overflow-x: auto; overflow-y: hidden;
/* Note: setting one axis to a non-visible value forces the other to
   'auto' — you cannot have visible on one and hidden on the other. */

/* Side effects of overflow != visible, all of which bite:
     - creates a block formatting context (stops margin collapsing)
     - BREAKS position: sticky for descendants
     - becomes the containing block for scroll calculations       */

/* overflow: clip avoids the scroll-container side effects, which
   makes it the better choice for pure clipping: */
.mask { overflow: clip }

/* Text overflow */
.truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
.clamp-3 { display: -webkit-box; -webkit-line-clamp: 3;
           -webkit-box-orient: vertical; overflow: hidden }
.break { overflow-wrap: break-word }      /* long URLs and tokens */

The Horizontal Scrollbar Hunt

The usual suspects, and how to find the culprit in one line.

Find the wide element, do not hide it
/* Find what is wider than the viewport */
document.querySelectorAll('*').forEach(el => {
  if (el.getBoundingClientRect().right > document.documentElement.clientWidth)
    console.log(el)
})

/* Or, visually */
* { outline: 1px solid red }

/* The usual causes:
     width: 100vw          — includes the scrollbar width on desktop,
                             so it is wider than the content area
     a negative margin
     position: absolute with a right offset outside the parent
     an unbroken long string
     a fixed-width image without max-width: 100%
     a table wider than its container                              */

/* Global guards worth having */
img, video, svg { max-width: 100%; height: auto }
body { overflow-x: hidden }     /* a plaster — it hides the symptom
                                   and can break sticky. Find the cause. */

/* Prefer 100% to 100vw for full-bleed sections, or account for the
   scrollbar: */
width: calc(100vw - (100vw - 100%));

Scroll Behaviour and Accessibility

Snapping, smooth scrolling, and the rule people miss.

tabindex, snap, overscroll-behavior
/* A scrollable region must be keyboard-reachable. Without tabindex,
   a keyboard-only user cannot scroll it at all. */
<div class="table-wrap" tabindex="0" role="region" aria-label="Results">

/* Scroll snapping — a carousel with no JavaScript */
.carousel {
  display: flex; gap: 1rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
}
.carousel > * { scroll-snap-align: start; flex: none; width: 80% }

/* Smooth scrolling, respecting the user's motion preference */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth }
}

/* Offsets for a sticky header, so anchors do not land underneath */
html { scroll-padding-block-start: 5rem }
section { scroll-margin-block-start: 5rem }

/* overscroll-behavior stops a scroll inside a modal from continuing
   into the page behind it — the "scroll chaining" annoyance */
.modal-body { overscroll-behavior: contain }

/* Styling scrollbars, without hiding them entirely */
.scroller { scrollbar-width: thin; scrollbar-color: var(--rule) transparent }
/* A hidden scrollbar removes the only visual signal that there is
   more content. Style it; do not delete it. */

Key Points to Remember

  • 1overflow: hidden clips content with no way to reach it; auto is usually what was intended
  • 2Any non-visible overflow creates a formatting context and breaks position: sticky for descendants
  • 3A scrollable container needs tabindex and a label, or keyboard users cannot scroll it
  • 4width: 100vw includes the scrollbar and is the most common cause of an unexpected horizontal scrollbar
  • 5scroll-padding offsets anchors under a sticky header, and overscroll-behavior: contain stops scroll chaining out of a modal

Interview Questions

Sign in to ask Aria
1

What is the difference between overflow: hidden, auto and clip?

Medium
2

How would you track down an unexpected horizontal scrollbar?

Medium
3

Why does a scrollable div need tabindex="0"?

Hard

Ask Aria about Overflow and Scrolling

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…