Disable body scroll while having a scrollable nav menu

Hello all,

I had been struggling with maintaining nav menu scroll functionality while disabling body scroll. It might be due to a bug in ios. I tried fs-attributes and the memberstack solution. They didn’t work for me (at least on ios). So I used GPT generate me a script for my custom nav and it works like a charm. Here is the code in case anyone is struggling.

Paste this inside head tag

<!-- Disable scrolling when nav is open -->
<style>
  @media (max-width: 991px) {
    .no-scroll {
      overflow: hidden;
    }
    .nav_menu {
      overflow-y: auto;
      max-height: 100vh; /* Ensure the nav_menu can scroll within the viewport */
      max-width: 100vh; /* Ensure the nav_menu fills width */
      -webkit-overflow-scrolling: touch; /* Enable momentum scrolling on iOS */
    }
  }
</style>
<!-- Disable scrolling when nav is open -->

Paste this before body tag

<!-- Disable scrolling when nav is open -->
<script>
  document.addEventListener('DOMContentLoaded', () => {
    // Only run the script if the viewport width is 991px or less
    if (window.innerWidth <= 991) {
      const body = document.body;
      const navMenu = document.querySelector('.nav_menu');
      const navButtons = document.querySelectorAll('.nav_button');
      const navMenuLinks = document.querySelectorAll('.nav_menu_link');
      const buttonWrappers = document.querySelectorAll('.button_wrapper');

      function preventScroll(event) {
        if (!navMenu.contains(event.target)) {
          event.preventDefault();
        }
      }

      function disablePageScroll() {
        body.classList.add('no-scroll');
        document.addEventListener('touchmove', preventScroll, { passive: false });
        document.addEventListener('wheel', preventScroll, { passive: false });
      }

      function enablePageScroll() {
        body.classList.remove('no-scroll');
        document.removeEventListener('touchmove', preventScroll, { passive: false });
        document.removeEventListener('wheel', preventScroll, { passive: false });
      }

      // Add event listeners to nav buttons to toggle page scroll
      navButtons.forEach(button => {
        button.addEventListener('click', () => {
          if (body.classList.contains('no-scroll')) {
            enablePageScroll();
          } else {
            disablePageScroll();
          }
        });
      });

      // Add event listeners to nav menu links and button wrappers to enable page scroll
      [...navMenuLinks, ...buttonWrappers].forEach(element => {
        element.addEventListener('click', enablePageScroll);
      });

      // Ensure that the nav menu itself is scrollable
      navMenu.addEventListener('touchstart', (e) => {
        e.stopPropagation();
      }, { passive: false });

      navMenu.addEventListener('touchmove', (e) => {
        e.stopPropagation();
      }, { passive: false });

      navMenu.addEventListener('wheel', (e) => {
        e.stopPropagation();
      }, { passive: false });
    }
  });
</script>
<!-- Disable scrolling when nav is open -->

Please be sure to change the class names.

For my nav it disables body scrolling while maintaining the scrollability of .nav_menu when nav open and and re-enables body scrolling when either nav is closed or any of these classes .nav_button; .nav_menu_link; and .button_wrapper are clicked.

Also, be sure to add an empty div at the bottom of your nav with a fixed height and/or padding in my case 24 rem worked the best so the div actually overflows even if there are browser components restricting your site’s UI visibiliy.

Hope this helps :slight_smile: