mapsteps / page-builder-framework

52 stars 17 forks source link

IOS (and Android) offcanvas + scrolling behaviour is a little erratic/jumpy (offcanvas scrolling bubbles up to body). Possible solution attached. #5

Closed gbruzzo closed 5 years ago

gbruzzo commented 5 years ago

Hello There,

Here is a possible solution for the 'offcanvas scrolling bubbling up to body scrolling' issue that has been known to plague all mobile webkit browsers, and which seems to show up in your framework as well. This results in quite unpleasant user experiences (the bottom of the offcanvas jumps revealing the body below scrolling - not nice). For Android browsers, it is my understanding, that it is usually enough to set overflow:hidden whenever an 'offcanvas is open' class is active (you have active-mobile in body). iOS requires different approaches

We tried different approaches (pure css as above with added position:fixed, a touchmove preventDefault/stoppropagation approach associated with the offcanvas container etc. They either completely failed or partially failed).

The approach below, based on

It borrows the open / close triggers from your mobile canvas.js

In Site-Child.js (or better if integrated into mobile-offcanvas.js, more conditions required to make it compatible with hamburger) enter:

var scrollposition = {x: window.scrollX, y: window.scrollY};

//Open Offcanvas $('.wpbf-mobile-menu-off-canvas .wpbf-mobile-menu-toggle').click(function() { scrollposition = {x: window.pageXOffset, y: window.pageYOffset}; $('body').css({height: window.innerHeight, 'overflow':'auto'}); $('html').css('margin-top', scrollposition.y * -1).addClass('offcanvas-active'); });

//Close Offcanvas $('.wpbf-mobile-menu-off-canvas .wpbf-close').click(function() { $('body').css({height: '', overflow:''}); $('html').css('margin-top', '').removeClass('offcanvas-active'); window.scrollTo(scrollposition.x, scrollposition.y); });

$(window).click(function() { if ( $('html').hasClass('offcanvas-active') ) { $('body').css({height: '', overflow:''}); $('html').css('margin-top', '').removeClass('offcanvas-active'); window.scrollTo(scrollposition.x, scrollposition.y); console.log(scrollposition.y); } });

in style.css enter

html.offcanvas-active { position: fixed;

}

.wpbf-mobile-menu-container nav { -webkit-overflow-scrolling: touch; overflow:scroll; }

.wpbf-mobile-menu-off-canvas .wpbf-mobile-menu-container { position: fixed; top: 0; bottom: 0; width: 320px;
z-index: 999999; }

That will take care of most issues.

You can see it at work here https://www.newrarenoise2.rarenoise.com

Deep regards for your beautiful framework, Mr Vongries.

Giacomo Bruzzo

gbruzzo commented 5 years ago

Hello there

a further development - it turns out the solution above results in unpleasant visual glitches in Safari desktop and iOS (the page jumping back and forth) - the problems does not occur in other browsers, but we could not mitigate it at all.

I therefore went back to the bodyScrollLock js package (https://www.npmjs.com/package/body-scroll-lock). I am pleased to say it can be made to work, out of the box.

to do so

  1. enqueue it in functions.php

wp_enqueue_script( 'body-scroll-lock', WPBF_CHILD_THEME_URI . '/js/bodyScrollLock.js', false, WPBF_CHILD_VERSION, true );

  1. add its logic to the child-site.js as in
(function($) {

/********* this code sorts out the scrolling body issue*****************/

    const targetElement = document.querySelector(".wpbf-mobile-menu-container");

//Open Offcanvas
$('.wpbf-mobile-menu-off-canvas .wpbf-mobile-menu-toggle').click(function() {
    $('body').addClass('offcanvas');
    bodyScrollLock.disableBodyScroll(targetElement);
});

//Close Offcanvas when clicking on close button
$('.wpbf-mobile-menu-off-canvas .wpbf-close').click(function() {
    bodyScrollLock.enableBodyScroll(targetElement);
    $('body').removeClass('offcanvas');
});

//Close Offcanvas when clicking anywhere on the window
$(window).click(function() {
    if ( $('body').hasClass('offcanvas') ) {
        bodyScrollLock.enableBodyScroll(targetElement);
        $('body').removeClass('offcanvas');
    }
});

})( jQuery );

Note that I had to add / remove a further class to body, because active-mobile has been already removed by the time the code checks. Integration of this plugin into mobile-offcanvas.js would probably allow this issue to be circumvented.

The following code is to be added to style.css

.wpbf-mobile-menu-container {
    -webkit-overflow-scrolling: touch;
    overflow: scroll;
}

.wpbf-mobile-menu-container nav {
    overflow-y: initial;
}

The code checks for webkit-overflow-scroll on the target element, so it must be there. overflow has to scroll. The overflow-y:auto in the child css has to be neutered.

This seems to work really quite well now. I would therefore suggest you look at this package more closely if you have the time.

Giacomo Bruzzo

mapsteps commented 5 years ago

Hi Giacomo,

thanks for providing all the details. I'll have a look at this after all the Black Friday buzz.

How can I recreate and test the actual issue with the off-canvas & scrolling behaviour?

Thanks!

Best, David

gbruzzo commented 5 years ago

Hello there!

to recreate the problem, just a standard installation with regular offcanvas mobile menu viewed / interacted with on an iOS device - iphone / ipad or on an iOS Simulator/XCode on Mac -offcanvas, scroll with our finger on the offcanvas (whether the length of your menu is larger or not than that page).

The attempted solutions are described here https://medium.com/jsdownunder/locking-body-scroll-for-all-devices-22def9615177 \ refers to https://www.npmjs.com/package/body-scroll-lock

Cheers

Giacomo

mapsteps commented 5 years ago

Hi @gbruzzo,

I can see the clipping at the bottom (on scroll), also happening on my Android device.

Regarding being able to scroll, I don't see that this is an issue. It can make sense to prevent people from scrolling while the menu is open, but I wouldn't want to force them to.

gbruzzo commented 5 years ago

Hi there - thanks for you response. The scrolling is quite a problem though, in particular if your offcanvas menu is longer than the viewport itself, and therefore itself needs to scroll. As the user moves her finger up and down the offcanvas touchmove will affect sometimes the background layer, sometimes the scrolling part of the menu. It’s not nice nor pleasant, even if one were able to block the clipping (which is a very bad effect to start with).

Using the body scroll lock is works very smoothly - see www.newrarenoise2.rarenoise.com

Cheers

Giacomo Bruzzo

On Tue, 27 Nov 2018 at 11:39 am, David Vongries notifications@github.com wrote:

Hi @gbruzzo https://github.com/gbruzzo,

I can see the clipping at the bottom (on scroll), also happening on my Android device.

Regarding being able to scroll, I don't see that this is an issue. It can make sense to prevent people from scrolling while the menu is open, but I wouldn't want to force them to.

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/MapSteps/Page-Builder-Framework/issues/5#issuecomment-442028265, or mute the thread https://github.com/notifications/unsubscribe-auth/AQBR-ufBpVByzpwFFAk5-aDmsnocu3nHks5uzSRogaJpZM4Ypoog .

mapsteps commented 5 years ago

Thanks for the live example. Looks great! Marked as enhancement & added to the roadmap.

mapsteps commented 5 years ago

Hi @gbruzzo,

I really see how this makes sense but I'd still like to close this for now for 2 reasons.

We could apply overflow: hidden to the body while the menu is open but that kind of feels like forcing users into something. I'd like to leave this optional.

A body class (active-mobile) is being added for the time the navigation is open. This can be used to apply overflow: hidden like so:

.active-mobile {
    overflow: hidden;
}

Also, since the off-canvas menu is set to position: fixed users can scroll inside the menu itself in case it gets longer as the viewport.

I know this is solving only half of the issue but I'd like to leave this optional for now and get back to it later if we get more request.