Articles

CSS overscroll-behavior Explained

overscroll-behavior stops scroll chaining and pull-to-refresh bounce at a container's edge. How the property works and when to use it.

Takina Takina · · 3 min read
Close-up of CSS code on a screen

The overscroll-behavior CSS property controls what happens when a user scrolls past the edge of a scrollable element — specifically, whether that extra scroll “leaks” out to the parent container or the page underneath. It’s the fix for the classic annoyance of scrolling to the bottom of a chat panel or modal and having the whole page start scrolling with it.

The problem: scroll chaining

By default, browsers implement scroll chaining: when a nested scrollable element (a div with overflow: auto, say) reaches its scroll boundary, any further scroll input is passed up to the next scrollable ancestor. Scroll to the bottom of a sidebar list, keep scrolling, and the main page content starts moving instead. On touch devices this is compounded by overscroll effects — the rubber-band bounce on iOS or the pull-to-refresh gesture on Android — which can trigger even when the user only meant to scroll within a nested box.

Both behaviors make sense as defaults for a single scrollable page, but they actively work against you in layouts with nested scroll regions: chat windows, modals, dropdown menus, code panels, carousels.

Syntax and values

.chat-panel {
  overflow-y: auto;
  overscroll-behavior: contain;
}
  • auto — the default. Scroll chains to the parent and overscroll effects (bounce, pull-to-refresh) apply normally.
  • contain — scrolling stops at the element’s boundary. The parent doesn’t scroll, but the element itself may still show a local bounce/glow effect at its own edge.
  • none — same as contain, but also suppresses the element’s own boundary overscroll effect entirely.

You can also set it per axis with overscroll-behavior-x and overscroll-behavior-y, which matters for anything that scrolls horizontally, like a carousel or a code block with long lines.

A practical example

A common source of user complaints: a modal dialog with scrollable content, opened over a long page. Without overscroll-behavior, scrolling to the end of the modal’s content and continuing to scroll moves the page behind it — the modal appears to let the background “escape.”

.modal-body {
  overflow-y: auto;
  overscroll-behavior-y: contain;
}

Setting contain on the modal body keeps scroll input inside the modal once it reaches either boundary. This pairs naturally with the HTML <dialog> element, which already traps focus and blocks interaction with the rest of the page — overscroll-behavior closes the remaining gap by trapping scroll too.

The same technique applies to chat interfaces, comment threads, and any fixed-height panel with its own scrollbar. It’s also worth setting on html or body with none if you’re building a full-screen app (a game, a map, a drawing tool) where you want to disable the browser’s pull-to-refresh gesture entirely.

overscroll-behavior vs touch-action

It’s easy to confuse overscroll-behavior with touch-action, but they solve different problems:

overscroll-behaviortouch-action
ControlsWhat happens at a scroll boundaryWhich gestures a browser handles natively at all
Typical useStop scroll chaining, disable bounce/pull-to-refreshDisable pinch-zoom, pan, or double-tap-to-zoom on an element
Affects mouse wheelYesNo, touch/pointer gestures only
Common valuecontainnone, pan-y, manipulation

touch-action governs whether the browser intercepts a gesture for its own default behavior (zooming, panning) versus handing it to your JavaScript. overscroll-behavior governs where scroll input goes once it’s already scrolling a box. They’re often used together on custom drag-and-drop or gesture-based UI, but neither substitutes for the other.

Browser support and fallbacks

overscroll-behavior is supported in all modern evergreen browsers. There’s no meaningful fallback needed — in browsers that don’t recognize the property, scroll chaining just behaves as it always did, which is a safe default degradation rather than a broken one. This makes it a low-risk property to add: it’s pure enhancement, similar in spirit to scroll-snap or container queries, where unsupported browsers simply ignore the rule rather than failing.

One caveat: overscroll-behavior: contain on an element only stops chaining to that element’s scroll ancestors. It doesn’t stop chaining if you also want to prevent, say, a nested scrollable element three levels down from chaining past its immediate parent to the grandparent — each boundary needs its own declaration if you want scroll fully contained at every level.

The takeaway

overscroll-behavior gives you control over scroll chaining and overscroll effects without JavaScript. Use contain on modals, chat panels, and other nested scroll regions to stop scroll from leaking into the page behind them; use none on full-screen apps to kill pull-to-refresh and rubber-banding outright. It’s a one-line, zero-risk addition to any layout with nested scrollable containers.

Takina Takina · · 4 min read

CSS field-sizing Property Explained

The CSS field-sizing property lets form controls like textareas grow to fit their content automatically, without JavaScript resize listeners.

#CSS #Web Development #Frontend