The overscroll-behavior
CSS property controls whether an element will use “scroll chaining” or not. You have likely experienced this behavior before and perhaps took it for granted that scrolling works like this on the web! If you are inside of an element that has its own scrolling (say it’s vertical) and you have scrolled down to the bottom of it, then by default, the next parent element up (maybe the page itself) starts to scroll in that direction. If you don’t want that default, overscroll-behavior
is what controls it.
In other words, it specifies how the browser behaves when reaching the boundary of a scrolling area.
.stop-scroll-chaining {
overscroll-behavior: contain; /* or "none" */
}
overscroll-behavior
is a shorthand for overscroll-behavior-x
and overscroll-behavior-y
and it is defined in the CSS Overscroll Behavior Module Level 1 Specification which is currently in Editor’s Draft status.
Scroll chaining and overscroll affordances
Scroll chaining is when scrolling is propagated from one scroll container to an ancestor scroll container. You can see this effect in following video:
As you can see, once the list box’s scroll boundary is reached, the container behind it starts to scroll and then the underlying page follows the scroll chain as well.
Overscroll affordance is stuff like the overscroll glow effect on Android or the rubber-banding effect on iOS, both of which serve as a visual indicator that the user has hit a scroll boundary. You may also see other implementations in the wild, like a “bounce” effect on mobile browsers or a page refresh when the top or bottom of a page is reached.
Syntax
overscroll-behavior: [ contain | none | auto ]{1,2}
- Initial value:
auto
- Applies to: non-replaced block-level elements and non-replaced inline-block elements
- Inherited: no
- Percentages: n/a
- Computed value: as each of the properties of the shorthand
- Animation type: discrete
Values
/* Keyword values */
overscroll-behavior: auto; /* default */
overscroll-behavior: contain;
overscroll-behavior: none;
/* Two values */
overscroll-behavior: none auto;
overscroll-behavior: auto contain;
/* Global values */
overscroll-behavior: inherit;
overscroll-behavior: initial;
overscroll-behavior: revert;
overscroll-behavior: unset;
auto
: The default value. Specifies that the browser should perform the default boundary action, and makes it possible for the user to continue scrolling through a parent scroll area when the boundary of the primary scroll area has been reached. In other words, it allows scroll chaining and overscroll affordances.contain
: Prevents scroll chaining. Scrolls do not propagate to ancestors (the other elements in a parent container) but preserve overscroll affordances like “bounce” effects when scrolling past the end of the container in operating systems that support it.none
: Prevents scroll chaining and also prevents overscroll affordances. So, you won’t get that Android overscroll glow or iOS rubber-banding effect.initial
: Applies the property’s default setting, which isauto
.inherit
: Adopts theoverscroll-behavior
value of the parent.unset
: Removes the currentoverscroll-behavior
from the element.
Constituent properties
We mentioned it earlier, but over scroll-behavior
is shorthand for two other CSS properties, which call the “constituent properties” of the shorthand. Let’s look at those individually.
overscroll-behavior-x
As the name suggests, the overscroll-behavior-x
CSS property allows you to control the browser’s behavior when the horizontal boundary of a scrolling area is reached. So, where we can control both the horizontal and vertical over scroll behavior with overscoll-behavior
alone, overscroll-behavior-x
only controls the behavior in the left and right direction.
In the following demo, you can see the different behavior of browser when the value of overscroll-behavior-x
is contain
:
See that? When contain
overscroll behavior is turned off, the whole page starts to scroll once you reach the horizontal (left and right)) scrolling boundary.
overscroll-behavior-y
The overscroll-behavior-y
CSS property is just like overscroll-behavior-x
but it controls the browser’s behavior when the vertical boundary of a scrolling area is reached. So, we’re talking about the top and bottom direction this time.
.modal {
overscroll-behavior-y: contain;
}
overscroll-behavior-inline
The overscroll-behavior-inline
CSS property allows you to control the browser’s behavior when the inline direction boundary of a scrolling area is reached.
overscroll-behavior-inline
is a CSS logical property that corresponds to the overscroll-behavior-x
of an element when the writing-mode
is horizontal, or the overscroll-behavior-y
of the element when the writing-mode
is vertical.
overscroll-behavior-block
The overscroll-behavior-block
CSS property allows you to control the browser’s behavior when the block direction boundary of a scrolling area is reached.
overscroll-behavior-block
is a CSS logical property that corresponds to the overscroll-behavior-y
of an element when the writing-mode
is horizontal, or the overscroll-behavior-x
of the element when the writing-mode
is vertical.
.element {
overscroll-behavior-block: none;
}
Usage
Wanna see a few examples of overscroll-behavior
in action? Of course you do!
Disabling the pull-to-refresh feature
Once the pull-to-refresh effect got very popular, mobile browsers, including Chrome on Android, implemented it as well. Swiping down at the top of the page refreshes the entire page.
As useful as this gesture is, sometimes you want to create your own pull-to-refresh effect, and need to disable the browser’s native overscroll action. We can make that happen by preventing scroll chaining on <html>
or <body>
:
html {
overscroll-behavior-y: contain;
}
This also prevents overscroll navigation actions.
Disabling overscroll glow and rubber-banding effects
Setting the contain
value doesn’t remove these effects. For this to work, we need to use the none
value, which also disables the pull-to-refresh and overscroll navigation actions.
html {
overscroll-behavior-y: none;
}
You might also want to use this with infinite scrolling. It might be confusing when a user reaches the bottom of page, gets a rubber-banding effect, then more content loads.
Preventing page content from scrolling underneath a modal or a fixed side navigation
Consider a side navigation with a large number of items — so many that the height of the navigation exceeds the page height and the user has to scroll down to see all of the menu items.
The overflow container stops scrolling when they reach the bottom, but if the user keeps scrolling, the rest of the content outside the navigation container starts scrolling as well.
Using contain
keyword prevents this:
We can use the same approach for modals:
Browser support
This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.
Desktop
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
65 | 59 | 11 | 79 | 16.0 |
Mobile / Tablet
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
123 | 124 | 123 | 16.0 |
I just learned about this CSS property. Total game changer! I feel like this is going to create a much more natural user experience.
I am looking for a solution to stop rubber band effect but keep the scroll chaining. Does anyone know a solution?
Awesome, until you’re trying to prevent it on iOS… Anyone found a workaround ?
Is there any polyfill available for this property? Apparently, Apple is not focusing on implementing new web APIs and CSS properties. Polyfills help tackle their ignorance in the most natural way possible imho.