Streaming live at 10am (PST)

How to prevent body from scrolling when modal window open

Hi @sabanna,

Thanks for this script it saves me a lot of time.
However, recently, I noticed that it doesn’t work anymore (when my modal is active, the body is still scrolling. But last month this piece of code was just working right…).
May be Webflow changed his settings about this…

I’ve just added “,html” just near “body” in the code and it worked for me.
I thought it could be helpful for anyone else…

Regards,
Alain

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.

Hello everyone!

I know it’s long time passed, but since many webflowers are using this workaround just wanted to share another code snippet that will work with :exclamation: Webflow navbar component. :exclamation:

This code will prevent the page from scrolling when a menu is open:

UPDATE:
There is a bug when iOS doesn’t prevent users from scrolling past the modal if there is content that exceeds the viewport height, despite adding overflow:hidden to the CSS.
iOS bug created in 2016 solved only in May 2019 but they have no idea when it will be released.
https://bugs.webkit.org/show_bug.cgi?id=153852
So I had to update the code below with the additional enhancement which detects the OS of the device and does a bit of a different approach if it is iOS.

<script>
// Detecting if it is an iOS device, true/false
  var iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform); 

  $(document).ready(function(){ 
    // Defining that "overlay" is the element that has a changing display value
    var overlay = document.querySelector('.w-nav-overlay');

    // Creating our mutation observer, which we attach to overlay later
    var observer = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutationRecord) {

        // Checking if it's the style attribute got changed and if display value now set to 'none'?
        if( mutationRecord.attributeName === 'style' && window.getComputedStyle(overlay).getPropertyValue('display') !== 'none'){

          //Overlay's  display value is no longer 'none', now changing the "body" styles:
          if (iOS) { 
            // for iOS devices:
            var x = $(window).scrollTop().toFixed()
            

            $('body').css({'overflow': 'hidden',
                           'position': 'fixed',
                           'top' : '-' + x + 'px',
                           'width': '100vw'});
          }
          // for all other devices:
          $('body').css('overflow', 'hidden');  
        } 
         //Overlay's  display value back to 'none' , now changing the "body" styles again:
         else {
               if (iOS) {
               //  for iOS devices:
                  var t = $('body').css('top').replace('-','').replace('px','')
                  $('body').css({'overflow': 'auto',
                                 'position': '',
                                 'width': '100vw'});
                  $('body').animate({scrollTop:t}, 0);
               }
              // for all other devices:
              $('body').css('overflow', '');

        }

      });    
    });
    // Attach the mutation observer to overlay, and only when attribute values change
    observer.observe(overlay, { attributes : true, attributeFilter : ['style']});

  });

</script>

The snippet can be used regardless of the class-names you are using in your project.

Happy designing!
Anna

5 Likes

There is a bug when iOS doesn’t prevent users from scrolling past the modal if there is content that exceeds the viewport height, despite adding overflow:hidden to the CSS.

iOS bug created in 2016 solved only in May 2019 but they have no idea when it will be released.
https://bugs.webkit.org/show_bug.cgi?id=153852

So I had to update the code (:point_up: in the previous comment) with the additional enhancement which detects the OS of the device and does a bit of a different approach if it is iOS.

2 Likes
<script>
Webflow.push(function() {
  $('.menu-button-class').click(function(e) {
    e.preventDefault();
	$('body').css('overflow', 'hidden');
  });

  $('.menu-class-name').click(function(e) {
    e.preventDefault();
	$('body').css('overflow', 'auto');
  });
});
</script>

Hi @sabanna

Is there a way to have the same element be the trigger to start and stop the scroll.

So on the first click the element disables scroll and on the second click it enables scroll?

I’m using this for a custom hamburger menu and want to use the same icon to open and close the menu.

Thanks,

James

Problem solved, I managed to figure it out.

Here is the script for anyone else who may need to use it:

<script>
Webflow.push(function() {
$('.menu-button-class').click(function(e) {
  var clicks = $(this).data('clicks');
  if (clicks) {
e.preventDefault();
$('body').css('overflow', 'auto');
  } else {
e.preventDefault();
$('body').css('overflow', 'hidden');
  }
  $(this).data("clicks", !clicks);
});
});
</script>
2 Likes

@jamesgreeny Unfortunately that snippet will not work on the iOS devices

I addressed my friend regarding this issue, he wasn’t a fan of solution suggested by sabanna as it seemed too complex for the issue at hand.

He rewrote one of the scripts provided on this thread to account for iOS webkit issues.

I had to add custom attribute to button element data-clicks=“0”

This works like a charm for my burger menu.

<script>
Webflow.push(function() {
  $('.menu-button-class').click(function(e) {
    e.preventDefault();

    var clicks = $(this).data('clicks');
        
    if (clicks) {
      $('body').css({
        overflowY: 'scroll',
        '-webkit-overflow-scrolling': 'touch',
        position: 'inherit',
        top: '0'
      });

      $(window).scrollTop($(this).data('offset'));
    } else {
      $(this).data('offset', window.pageYOffset);
      
      $('body').css({
        overflowY: 'hidden',
        height: 'auto',
        position: 'absolute',
        top: 0 - window.pageYOffset
      });      
    }

    $(this).data("clicks", !clicks);
  });
});
</script>