Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent body from scrolling with Responsive menu

I am trying to properly implement the Responsive Menu plugin into a wordpress theme. The issue appears when the push-side menu is open, which cause body to move at vertical scroll.

At this moment, there is a solution for this template page that is working amazing and I'm happy with the result.

The question: Taking in consideration Outsource WordPress's answer, which fix the above specified page, is there any possibility to tweak the below code in order to be usable in more general way in other template pages as well for example here like already is running here?

I suppose that .edge-ils-item-link and .edge-ils-content-table are variables but I have no idea how to approach and adapt this, I've made some tests replacing these elements but with no positive results, maybe it's not that simple, it's more than that. I also know that edge-wrapper, edge-wrapper-inner, wpb_wrapper are found in every pages, these could be the common elements that could change the solution making it available for every page.

Also it will be great to be jQuery ready according to the latest version (at this point I am using jQuery migrate 1.4.1 and an old version of Wordpress in order to be functional at least on the page designed for).

.scroll-lock{position:fixed !important;}

$(document).ready(function() {
    var windowTop = 0;
    var menuOpen = 0;
    var offsetContainerList = 0;

    $('#responsive-menu-pro-button').click(function() {
        var offsetScrollList = $('.edge-ils-item-link:first').offset().top; 

        if ($('html').hasClass('scroll-lock')) {
            $('#responsive-menu-pro-container').one("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend",
              function(event) {
                  if (menuOpen==0) {
                      menuOpen = 1;
                      $('html').removeClass('scroll-lock');  
                      $('.edge-ils-content-table').css('top', eval(offsetContainerList)-40+'px'); //change image container top position
                      $('html').scrollTop(windowTop); //scroll to original position
                  }
                  else {   
                      menuOpen = 0;             
                  }
            });
        }
        else {                
            windowTop = $(window).scrollTop();
            offsetContainerList = $('.edge-ils-content-table').offset().top;  
            $('html').addClass('scroll-lock');      
            $('.edge-ils-content-table').css('top', -offsetScrollList + 'px'); //change image container top position
        }      
    }); 
}); 

Video with the issue, if this helps here.

like image 371
typo_ Avatar asked Jan 31 '21 19:01

typo_


2 Answers

Ok, first lets talk about the issue:

The plugin is setting transform: translateX(800px); on your main div, but, transform remove the position: fixed from all of its children, so all your inner divs that have position fixed, are basically moved to be position relative so they are basically moved to the top.

The Too Complex Solution:

You can of course play with scrolling the user to the top, saving what position he was, and do a real complex solution to workaround this issue, BUT, all of this for a left menu? it seems to be so much work for a simple fixed div that push other fixed div to the right.

The Easy Solution: Why wouldn't we just omit the transform, and use margin-left?

<style>

html.responsive-menu-pro-open {
  overflow-y: hidden !important;
  padding-right: 9px;
} 

#responsive-menu-pro-container {
  position: fixed !important;
}

#responsive-menu-pro-container {
  position: fixed !important;
  transform: none !important;
  margin-left: -800px;

  transition: 2.6s ease; 
  transition-timing-function: cubic-bezier(0.96, 0, 0.13, 1); 
  transition-property: margin-left; 
}

#responsive-menu-pro-button {
  transform: none !important;
  transition: 2.6s ease !important; 
  transition-timing-function: cubic-bezier(0.96, 0, 0.13, 1) !important; 
  transition-property: margin-left !important;
}

.responsive-menu-pro-open #responsive-menu-pro-button {
   margin-left: 800px;
}

#responsive-menu-pro-header {
  transform: none !important;
  transition: 2.6s ease; 
  transition-timing-function: cubic-bezier(0.96, 0, 0.13, 1); 
  transition-property: margin-left; 
}

.responsive-menu-pro-open #responsive-menu-pro-header {
  margin-left: 800px;
}

.responsive-menu-pro-open .edge-wrapper {
  transform: none !important;
}

.responsive-menu-pro-open .edge-wrapper .edge-wrapper-inner {
  margin-left: 800px;
}

.edge-wrapper .edge-wrapper-inner {
  transition: 2.6s ease; 
  transition-timing-function: cubic-bezier(0.96, 0, 0.13, 1); 
  transition-property: margin-left; 
}

.responsive-menu-pro-open .edge-content .edge-ps-navigation {
  margin-left: 800px;
}

.edge-content .edge-ps-navigation {
  transition: 2.6s ease; 
  transition-timing-function: cubic-bezier(0.96, 0, 0.13, 1); 
  transition-property: margin-left; 
}

.responsive-menu-pro-open #responsive-menu-pro-container {
  margin-left: 0;
  transition: 2.6s ease; 
  transition-timing-function: cubic-bezier(0.96, 0, 0.13, 1); 
  transition-property: margin-left; 
}

.responsive-menu-pro-open .edge-back-to-top-text {
  display: none;
}

</style>

By adding the snippet above, you mimic the functionality you want without transform using margin-left.

Notes - because of your page layout (its a bit of a mess, a lot of position fixed elements, inside other position fixed elements), you need to set margin-left to different elements, changing the page layout would make it much easier to apply this, or even use the native transform functionality of the plugin.

This solution might only work on the example page you gave us, you will need to set marign-left on the correct elements on your other pages, but again, if you layout all of your pages into a single wrapper div, that will hold the functionality, and remove other fixed elements, you will be able to create a single code snippet that will work on pages.

Bottom line - the plugin have issues because of your page layout, contacting the plugin developers might give you a better answer, and they might look into your specific theme and bring a much better solution. Without seeing your code this is the best work-around I could find without trying to play with scrolls.

like image 72
Art3mix Avatar answered Oct 17 '22 13:10

Art3mix


I noticed that the class of scroll-lock is not getting added to the html element in your page called "scroll-lock", but it is added on the "ilinks-push" page. So the if checking if the html has this class will never become true on your sub pages. I rewrote the code so it will look for the inteded class called responsive-menu-pro-open.

But moreover to make it work for your subpages, you need to understand the logic in the provided code. I did some changes and added comments to make it more clear:

$(document).ready(function() {
    var windowTop = 0;

    $('#responsive-menu-pro-button').click(function() {

        /* check if there is a ils item link */
        if ( $('.edge-ils-item-link')[0] ) {
            /* save space above the element to variable */
            var offsetScrollList = $('.edge-ils-item-link:first').offset().top;
        }

        /****** Menu gets opened ******/

        if ($('html').hasClass('responsive-menu-pro-open')) {

            /* scroll to top of page */
            windowTop = $(window).scrollTop(); 
            /* add the scroll-lock class */
            $('html').addClass('scroll-lock');
            
            /* check if there is a ils item link */
            if ( $('.edge-ils-item-link')[0] ) {
                /* add the saved space again to look like the same scroll position we started with */      
                $('.edge-ils-content-table').css('top', -offsetScrollList + 'px'); 
            }
            
        }

        /****** Menu gets closed ******/

        else { 
            $('html').removeClass('scroll-lock');

            /* check if there is a ils item link */
            if ( $('.edge-ils-item-link')[0] ) {
                /* again use the saved space to make it look like the start position */
                $('.edge-ils-content-table').css('top', -offsetScrollList +'px');
            }

            $('html').scrollTop(windowTop);
        }

    }); 
}); 

You see the parts where there is check if there is a ils item link written?

This will be the parts that are different on your subpages.

With using .offset().top we are getting the space above the elements. This will only work, if there are actually elements with the class of .edge-ils-item-link which is why I put the code inside of the if clauses.

In the code you are using the spaces above to position the elements in the right place, so it will look like the scroll is blocked.

To target the right elements, we need the class of it.

So you have to make sure, that every page uses the same class around the content area. This way you are able to target them on every page without additional if clauses in the javascript.

Alternatively you could right a bounch of if clauses and check the elements in your pages. In your page called "scroll-lock" it might be the element of info-field you can use to set the spaces. But in this page you have the content placed with fixed position (don't know why, are you using some fancy block builder or something? markup looks aweful), so this causes problems, when adding your class of scroll-lock with the position: fixed;.

I think you need to adjust the content of your other pages, so this problem can be solved for you. It will not be a good practice to adjust the javascript for every of your subpage with different content elements. Try to make every subpage in two columns (using flexbox). Maybe the left one will always be fixed and the right one is static and therefore scrollable. We don't know this with the information given in your question.

like image 23
rank Avatar answered Oct 17 '22 11:10

rank