Site logo

[Support request] Prevent body scroll for modals/ overlays

Home Forums Support [Support request] Prevent body scroll for modals/ overlays

Home Forums Support Prevent body scroll for modals/ overlays

Viewing 15 posts - 1 through 15 (of 20 total)
  • Author
    Posts
  • #2417989
    Dorin

    I’m in need of a solution that prevents body scrolling when modals are open on every device, os and web browser. It seems CSS only can’t achieve what I’m after. I stumbled upon this script that does exactly that. Now I tried loading the script via the cdn files using a hook element. My code looks something like this (I targeted the off canvas menu) – but it doesn’t work:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/body-scroll-lock/3.1.5/bodyScrollLock.min.js" integrity="sha512-HowizSDbQl7UPEAsPnvJHlQsnBmU2YMrv7KkTBulTLEGz9chfBoWYyZJL+MUO6p/yBuuMO/8jI7O29YRZ2uBlA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/body-scroll-lock/3.1.5/bodyScrollLock.es6.min.js" integrity="sha512-HCiqK+5xnhw9WYQN+BP6yKFr6iZ+euY5CtCVw/q//BLb3X7xsYNYB+/cCWhzE1m39WfDaXnaNZeDa4++lMKHtQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/body-scroll-lock/3.1.5/bodyScrollLock.esm.min.js" integrity="sha512-1D7ifQ1x2RpCxn+WK5i9bAUQ4KlK2BETBSgMOf+clTopmDVxkBBXcUgK7UA5LQ4kcgvqEcxLlnwvVQq1fgIPfw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    
    <script>
    const bodyScrollLock = require('body-scroll-lock');
    const disableBodyScroll = bodyScrollLock.disableBodyScroll;
    const enableBodyScroll = bodyScrollLock.enableBodyScroll;
    	
    const targetElement = document.querySelector('#generate-slideout-menu');	
    disableBodyScroll(targetElement);
    enableBodyScroll(targetElement);
    </script>

    I know it’s not a css specific question, but any idea on how to achieve a proper body scroll lock when a modal is open is greatly appreciated. Most of my pages use overlay modals (I’m leaving an example). I’m just trying to enhance the user experience, especially on mobile.

    #2418323
    David
    Staff
    Customer Support

    Hi there,

    is it just for the Off canvas ? if so – what about this CSS:

    
    .slide-opened body {
        max-height: 100vh;
        overflow: hidden;
    }
    .slide-opened #generate-slideout-menu {
        overflow: scroll;
    }
    #2418357
    Dorin

    Works well, David. Thanks. Do you think I can make it work for the modals in the page I left privately? That’s my main issue right now.

    #2418373
    David
    Staff
    Customer Support

    Ok, its possible but not in its present state.
    Where does the modal script come from? As currently it simply changes an inline style to show the modal, and we need it to toggle a class on the body or better still the html element.

    #2418391
    Dorin

    The script sits below the html in the custom html block on the page. I took the code from this codepen.

    #2418410
    David
    Staff
    Customer Support

    Ok, so thats good as you can edit it.
    At the top of the script add:

    var rootHTML = document.getElementsByTagName( 'html' )[0]

    This will load the HTML element into the rootHTML variable.

    Then in your script there are two click events:

    
    modal_btn_multi[i].onclick = function() {
        var ElementIndex = this.getAttribute('data-index');
        modalparent[ElementIndex].style.display = "block";
    };
    
    // When the user clicks on <span> (x), close the modal
    span_close_multi[i].onclick = function() {
        var ElementIndex = this.getAttribute('data-index');
        modalparent[ElementIndex].style.display = "none";
    };

    change them to:

    
    modal_btn_multi[i].onclick = function() {
        var ElementIndex = this.getAttribute('data-index');
        modalparent[ElementIndex].style.display = "block";
        rootHTML.classList.add('modal-open');
    };
    
    // When the user clicks on <span> (x), close the modal
    span_close_multi[i].onclick = function() {
        var ElementIndex = this.getAttribute('data-index');
        modalparent[ElementIndex].style.display = "none";
        rootHTML.classList.remove('modal-open');
    };

    This should now toggle the modal-open class on the HTML Element.

    And then our CSS becomes:

    
    .slide-opened body,
    .modal-open body {
        max-height: 100vh;
        overflow: hidden;
    }
    .slide-opened #generate-slideout-menu,
    .modal-open .modal  {
        overflow: scroll;
    }
    #2418523
    Dorin

    Made all the updates, but now the modals are not opening.

    #2419387
    David
    Staff
    Customer Support

    OK,

    reverse the changes to the Javascript.
    keep the CSS.
    Now add this script to your footer:

    var observer = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutationRecord) {
        rootHTML.classList.toggle('modal-open');
      });    
    });
    var rootHTML = document.getElementsByTagName( 'html' )[0];
    var modals = document.querySelectorAll('.modal');
    
    modals.forEach(modal => {
      observer.observe(modal, { 
        attributes: true, 
        attributeFilter: ['style'] 
      });
    });

    This should observe any changes to the modal elements styles and add the modal-open class to the HTML node.

    #2419464
    Dorin

    Still not working unfortunately. Sorry to bug you with this issue.

    #2419561
    David
    Staff
    Customer Support

    I can see the Class being toggled on the head, so the JS is working.
    Did you change the CSS to:

    .slide-opened body,
    .modal-open body {
        max-height: 100vh;
        overflow: hidden;
    }
    .slide-opened #generate-slideout-menu,
    .modal-open .modal  {
        overflow: scroll;
    }
    #2419567
    Dorin

    Yes, that code is in place. It’s working for the offcanvas menu, but not for the rest of the modals.

    #2419595
    David
    Staff
    Customer Support

    You have this CSS for the tablet:

    /* Tablet view */
    @media(max-width: 1024px) and (min-width: 769px) {
    	.separate-containers .inside-article, .inside-header, .inside-site-info {
    		padding-left: 20px;
    		padding-right: 20px;
    	}
    	
    	.swiper-button-next, .swiper-button-prev {
    		display: none;
    	}
    	
    	body .main-navigation.offside {
        width: 50%;
    }

    Is missing a closing } for the @media query.
    It should be:

    /* Tablet view */
    @media(max-width: 1024px) and (min-width: 769px) {
    	.separate-containers .inside-article, .inside-header, .inside-site-info {
    		padding-left: 20px;
    		padding-right: 20px;
    	}
    	
    	.swiper-button-next, .swiper-button-prev {
    		display: none;
    	}
    	
    	body .main-navigation.offside {
                width: 50%;
            }
    }

    Without that, the CSS below it is being included inside that media query

    #2419660
    Dorin

    Brilliant stuff, David. It’s working now. Sorry about forgetting to close that piece of code.
    The only area where it seems to not work everytime (on some modals it’s working, on others it doesn’t, espcially the last one in the list) is on Safari for mobile. What happens is the vertical scrollbar of the body remains visible sometimes and that triggers the scroll. Any chance to hide the vertical scrollbar of the body?

    #2419687
    David
    Staff
    Customer Support

    Hmmm… tricky one.
    What if we move the ovrflow scroll to the modal-content in the CSS ie.

    
    .slide-opened body,
    .modal-open body {
        max-height: 100vh;
        overflow: hidden;
    }
    .slide-opened #generate-slideout-menu,
    .modal-open .modal-content  {
        overflow: scroll;
    }
    #2420027
    Dorin

    The same behaviour. Sometimes works, other times the scroll gets activated. Some resources on the web suggest adding position: fixed; to the body element when the modal is open. Don’t know exactly how to implement it.

Viewing 15 posts - 1 through 15 (of 20 total)
  • You must be logged in to reply to this topic.