Preventing body scrolling while allowing overlay scrolling is a common requirement in web development, particularly when creating modal windows or overlays. In this tutorial, we will explore how to achieve this using CSS and JavaScript.
Understanding the Problem
When an overlay is opened, it’s often desirable to prevent the underlying body content from scrolling. This ensures that the user’s attention remains focused on the overlay and prevents any unnecessary scrolling.
Solution Overview
To solve this problem, we can use a combination of CSS properties, including overflow
, position
, and inset
. We will also use JavaScript to toggle classes and handle events.
Step 1: Creating the Overlay
First, let’s create the overlay HTML structure:
<button type="button" class="open-overlay">OPEN LAYER</button>
<section class="overlay" aria-hidden="true" tabindex="-1">
<div>
<h2>Hello, I'm the overlayer</h2>
<!-- overlay content -->
<button type="button" class="close-overlay">CLOSE LAYER</button>
</div>
</section>
Step 2: Styling the Overlay
Next, let’s add the necessary CSS styles:
.noscroll {
overflow: hidden;
}
.overlay {
position: fixed;
overflow-y: scroll;
inset: 0;
}
[aria-hidden="true"] {
display: none;
}
[aria-hidden="false"] {
display: block;
}
In this example, we’re using the inset
property to set the overlay’s position to fill the entire viewport. We’re also setting overflow-y
to scroll
to allow scrolling within the overlay.
Step 3: Toggling Classes and Handling Events
Now, let’s add the JavaScript code to toggle classes and handle events:
var body = document.body,
overlay = document.querySelector('.overlay'),
overlayBtts = document.querySelectorAll('button[class$="overlay"]'),
openingBtt;
[].forEach.call(overlayBtts, function(btt) {
btt.addEventListener('click', function() {
var overlayOpen = this.className === 'open-overlay';
/* Toggle the aria-hidden state on the overlay and the no-scroll class on the body */
overlay.setAttribute('aria-hidden', !overlayOpen);
body.classList.toggle('noscroll', overlayOpen);
/* On some mobile browser when the overlay was previously opened and scrolled, if you open it again it doesn't reset its scrollTop property */
overlay.scrollTop = 0;
/* forcing focus for Assistive technologies but note:
- if your modal has just a phrase and a button move the focus on the button
- if your modal has a long text inside (e.g. a privacy policy) move the focus on the first heading inside the modal
- otherwise just focus the modal.
When you close the overlay restore the focus on the button that opened it */
if (overlayOpen) {
overlay.focus();
} else {
openingBtt.focus();
}
});
});
In this example, we’re toggling the aria-hidden
attribute on the overlay and the noscroll
class on the body. We’re also handling events to focus on the overlay or the button that opened it.
Alternative Solutions
There are alternative solutions available, including using the overscroll-behavior
CSS property or adding position: fixed
to the .noscroll
class. However, these solutions may have limitations or require additional workarounds.
Conclusion
Preventing body scrolling while allowing overlay scrolling is a common requirement in web development. By using a combination of CSS properties and JavaScript events, we can achieve this effect while ensuring accessibility and usability.
Example Use Cases
- Modal windows
- Overlays with scrolling content
- Full-screen overlays with scrolling content
By following the steps outlined in this tutorial, you can create overlays that prevent body scrolling while allowing overlay scrolling, providing a better user experience for your website or application.