Preventing Body Scrolling while Allowing Overlay Scrolling

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.

Leave a Reply

Your email address will not be published. Required fields are marked *