overscroll-behavior-y

Controls vertical overscroll behavior independently. Used to selectively prevent vertical scroll propagation from a scrollable area to its parent.

Class List

ClassCSSDescription
obyaoverscroll-behavior-y: autodefault; propagates to parent at vertical scroll boundary
obycoverscroll-behavior-y: containblocks vertical scroll propagation
obynoverscroll-behavior-y: noneblocks both vertical propagation and bounce effects

Live Demo

The outer box and the inner box each scroll vertically. Scroll the inner box to its bottom, then keep scrolling instead of stopping. On the left the outer box continues moving (scroll chaining); on the right the movement stops inside.

Default (auto) — no class

Content of the outer container. It only exists to give the outer box enough height to scroll vertically.

Content of the inner scroll area. Scroll to the very bottom, then try to scroll once more.

Content of the inner scroll area. Scroll to the very bottom, then try to scroll once more.

Content of the inner scroll area. Scroll to the very bottom, then try to scroll once more.

Content of the inner scroll area. Scroll to the very bottom, then try to scroll once more.

Content of the inner scroll area. Scroll to the very bottom, then try to scroll once more.

Content of the inner scroll area. Scroll to the very bottom, then try to scroll once more.

Content of the outer container. It only exists to give the outer box enough height to scroll vertically.

Content of the outer container. It only exists to give the outer box enough height to scroll vertically.

When the inner scroll hits its edge, the leftover scroll is handed to the outer container. In a real product this shows up as the page behind a modal sliding away while you scroll the modal.

Propagation blocked — obyc

Content of the outer container. It only exists to give the outer box enough height to scroll vertically.

Content of the inner scroll area. Scroll to the very bottom, then try to scroll once more.

Content of the inner scroll area. Scroll to the very bottom, then try to scroll once more.

Content of the inner scroll area. Scroll to the very bottom, then try to scroll once more.

Content of the inner scroll area. Scroll to the very bottom, then try to scroll once more.

Content of the inner scroll area. Scroll to the very bottom, then try to scroll once more.

Content of the inner scroll area. Scroll to the very bottom, then try to scroll once more.

Content of the outer container. It only exists to give the outer box enough height to scroll vertically.

Content of the outer container. It only exists to give the outer box enough height to scroll vertically.

The outer container stays put even when the inner scroll reaches its edge, so a modal or chat panel never pushes the page behind it.

Per-class Detail

obyaoverscroll-behavior-y: auto

The browser default. When vertical scrolling reaches the edge, the remaining scroll amount goes to the parent scroll container or the page, and on mobile it comes with pull-to-refresh and the rubber-band effect.

When to use

Use it to bring one area back to default behavior inside a structure where obyc or obyn is applied further up.

<!-- Default: vertical scroll chains to the page -->
<div class="obya oya h30rem bg0F0F17 br8px p2rem">
  <p>Reaching the bottom continues scrolling the page.</p>
</div>

obycoverscroll-behavior-y: contain

Stops the leftover scroll from reaching the parent or the page when the vertical edge is hit, while keeping the element's own bounce effect.

When to use

The default choice for vertical scroll areas layered over the page: modal bodies, sidebars, dropdown lists, chat message panes. It replaces most JavaScript body-scroll-lock workarounds.

<!-- Chat panel that keeps its scroll to itself -->
<div class="obyc oya h50rem bg18181B br8px p16px">
  <div class="mb12px">Message 1</div>
  <div class="mb12px">Message 2</div>
  <div class="mb12px">Message 3</div>
</div>

obynoverscroll-behavior-y: none

On top of blocking propagation, it also removes the element's own bounce effect and pull-to-refresh.

When to use

Use it on the root scroll area of a full-screen web app that has to feel native. On an ordinary document page it takes away the refresh gesture users expect.

<!-- App shell: no chaining, no pull-to-refresh, no bounce -->
<main class="obyn oya h100vh bg0F0F17">
  <section class="p2rem">App content</section>
</main>

Usage Examples

The basic form for blocking vertical scroll propagation.

<!-- Modal: block only vertical scroll propagation -->
<div class="obyc oya h30rem bg0F0F17 br8px p2rem">
  <p>Vertical scroll does not propagate to parent at the end.</p>
  <p>Horizontal scroll maintains default behavior.</p>
</div>

<!-- Prevent pull-to-refresh -->
<body class="obyc">
  <main class="oya h100vh">
    Pull-to-refresh does not work on mobile.
  </main>
</body>

<!-- Chat area: independent scroll -->
<div class="chat-messages obyc oya h50rem bg18181B p16px">
  <div>Message 1</div>
  <div>Message 2</div>
  <div>Message 3</div>
</div>

Applied to a modal body: the page behind stays still even when the body scroll reaches its top or bottom edge.

<!-- Modal body that must never scroll the page behind it -->
<div class="pf t0 l0 w100p h100vh bg0-0-0-50 df jcc aic zi100">
  <div class="w50rem maxw100p bg0F0F17 b1pxsolid27272A br12px oh">
    <header class="py16px px2rem bb1pxsolid27272A">
      <h2 class="fs2rem fw700 cFAFAFA">Terms of service</h2>
    </header>

    <!-- obyc keeps the wheel inside this body once it hits top or bottom -->
    <div class="obyc oya maxh50vh py16px px2rem fs14px cA1A1AA lh1-7">
      <p class="mb16px">Long agreement text...</p>
      <p class="mb16px">Long agreement text...</p>
    </div>

    <footer class="py16px px2rem bt1pxsolid27272A df jcfe gap8px">
      <button class="py8px px16px bg18181B cFAFAFA br8px bn cp">Cancel</button>
      <button class="py8px px16px bg6366F1 cFFFFFF br8px bn cp">Agree</button>
    </footer>
  </div>
</div>

Tips & Notes

Preventing mobile pull-to-refresh

Apply obyc to the top-level page element to block the mobile browser's pull-to-refresh behavior.

Only meaningful on a scrollable element

overscroll-behavior-y only applies when the element really is a vertical scroll container. It needs an overflow class such as oya together with a height limit, and nothing happens if the content does not overflow.

contain versus none

obyc blocks propagation to the parent but keeps the element's own bounce. obyn removes the bounce and pull-to-refresh too. For modals and chat panels, contain is enough.

An alternative to body scroll locking

If you have fought with setting overflow hidden on body when a modal opens and then losing the scroll position, applying obyc to the modal body is simpler and has fewer side effects.