CSS overscroll-behavior Only Affects Scroll Containers
Four years ago, I discovered the overscroll-behavior
CSS property and it rocked my world! This CSS property prevents a scroll operation from bubbling up to its parent container once a local scroll maxima/minima is reached (a behavior known as "scroll chaining"). What I didn't realize at the time, however, is that the overscroll-behavior
property only applies to "scroll containers". That is, it only applies to elements that have a scrollbar / scrolling content. As such, it has no effect whatsoever on non-scrolling containers.
Run this demo in my JavaScript Demos project on GitHub.
View this code in my JavaScript Demos project on GitHub.
To see this divergent effect in the browser DOM (Document Object Model), let's create a simple page that has a two-panel modal window. In this modal, the top panel (header) is not a scrolling container whereas the body panel is. Both panels will have the overscroll-behavior
property applied to it; but, it will only have a tangible affect on the scrolling panel:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="./main.css" />
<style type="text/css">
.modal {
display: flex ;
flex-direction: column ;
}
.modal__header {
flex: 0 0 auto ;
overscroll-behavior: contain ; /* !! NOT !! on a SCROLL CONTAINER. */
}
.modal__body {
flex: 1 1 auto ;
overflow: auto ;
overscroll-behavior: contain ; /* Is on a SCROLL CONTAINER. */
}
</style>
</head>
<body>
<h1>
CSS overscroll-behavior Only Affects Scroll Containers
</h1>
<!-- BEGIN: Modal (w/ Scrolling Body Panel). -->
<section class="modal">
<div class="modal__header">
This is a modal
</div>
<div class="modal__body">
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
</div>
</section>
<!-- END: Modal. -->
<!-- Body content, lots of it, scrolling main page. -->
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
</body>
</html>
As you can see from the <style>
block, both panels in the modal have overscroll-behavior: contain
on them. However, if we load this page in the browser and use the mouse wheel while over both of the panels, what we can see is that only the scrolling panel blocks and contains the scroll operation.
As you can see, when I use my mouse wheel over the scrolling panel, the overscroll-behavior
property successfully prevents the scroll operation from bubbling up to the main body. However, when I use my mouse wheel over the header panel - which has no overflow - the scroll operation bubbles up to the parent and ends up scrolling the main body.
The overscroll-behavior
property is still awesome; but, I clearly had a big hole in my mental model for how it works.
Want to use code from this post? Check out the license.
Reader Comments
Thanks for this discovery, Ben. Have you encountered any remedy by any chance? This is an issue that I hope to find a solution for. Very tricky. When the modal has input type=text with that focused--imagine a dialog for an email subscription--, the scroll for the modal is not contained either.
@Hwi,
When it comes to modal windows, I've taken to actually removing the scroll on the
body
itself while the modal is open. This way, even if the user does scroll with their mouse, there's no scrolling container to capture it in the root of the document.Take a look at this post which demonstrates my technique:
www.bennadel.com/blog/4442-using-a-transient-css-stylesheet-to-remove-scrolling-on-body-while-modal-is-open.htm
It applies / removes a
<style>
block to the document while the modal window is open.Is there another way instead of "overflow hidden" on body element? Because if I add and remove "overflow hidden", the scrollbar disappears and appears, which will make the page width shaking.
The thing I want is "overscroll-behavior contain" making effect on non-scrollable div.
@Jarvis,
In my experience, having the width of the page change my a small amount usually isn't a problem since it's happening in conjunction with another large UI change (such as showing a modal window). Only to say that the small change isn't that noticeable.
That said, I believe that if you want to apply this kind of behavior to a non-scrolling element, you have to do it via JavaScript. I haven't done this in a while, but I think you have to bind to the
mousewheel
event (as well as other non-standard events likewheel
), and then call.preventDefault()
on it; or maybe.stopPropagation()
. I can't really remember all the details. But, basically you have to tap into the "wheel" action and prevent that from being consumed by the browser.I have a bit of an exploration here:
www.bennadel.com/blog/3544-trapping-the-wheel-event-may-prevent-chrome-browser-bug-in-which-the-scroll-wheel-stops-working-in-overflow-container.htm
That post is in relational to scrollable areas; but, the outcome would be the same, I think.
Post A Comment — ❤️ I'd Love To Hear From You! ❤️
Post a Comment →