juniortan
juniortan

Reputation: 206

BootStrap Modal background scroll on iOS

So there is this known issue with modal on iOS, when the modal is enabled swiping up/down will scroll the body instead of the modal.

Using bootstrap 3.3.7

Tried to google it, most suggested adding

body.modal-open {
  overflow: hidden !important;
}

but it doesn't work.

Some suggested,

body.modal-open {
  position: fixed;
}

But background will jump to the top of the page.

So for now I am using,

body.modal-open {
  overflow: hidden !important;
  position: fixed;
  width: 100%;
}
#exampleModal {
  background: black;
}

As a work-around so the jump can't be seen(but still noticeable)

Is there other solutions to this?

This is the site i am working on http://www.einproductions.com/

Upvotes: 15

Views: 21060

Answers (6)

trop yes
trop yes

Reputation: 57

This will prevent page scrolling while Modal is opened on iOS mobile

if ($(window).width() < 960) {
        let previousScrollY = 0;
        $(document).on('show.bs.modal', () => {
            previousScrollY = window.scrollY;
            $('html').addClass('modal-open').css({
                marginTop: -previousScrollY,
                overflow: 'hidden',
                left: 0,
                right: 0,
                top: 0,
                bottom: 0,
                position: 'fixed',
            });

        }).on('hidden.bs.modal', () => {
            $('html').removeClass('modal-open').css({
                marginTop: 0,
                overflow: 'visible',
                left: 'auto',
                right: 'auto',
                top: 'auto',
                bottom: 'auto',
                position: 'static',
            });
            window.scrollTo(0, previousScrollY);
        });
    }

Upvotes: 0

Kuldeep Bhimte
Kuldeep Bhimte

Reputation: 959

Import this file and use the enableBodyScroll and disableBodyScroll functions to lock and unlock the body scroll.

using css top property will exactly navigate back to the previous position. It eliminate the drawback of dealing with the floating point margin.

const toggleBodyScroll = (position, initialMargin) => {
  document.body.style.position = position;
  document.body.style.top = initialMargin;
};

const getScrolledPosition = () => {
  return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
};

const scrollToPrevPosition = (scrolledPosition) => {
  window.scrollTo(0, scrolledPosition);
};

const getWindowTop = () => {
  return window.getComputedStyle(document.body).getPropertyValue('top');
};

export const disableBodyScroll = () => {
  toggleBodyScroll('fixed', `-${getScrolledPosition()}px`);
};

export const enableBodyScroll = () => {
  const scrollPosition = 0 - parseInt(getWindowTop());
  toggleBodyScroll('static', 0);
  scrollToPrevPosition(scrollPosition);
};

Upvotes: 0

kofifus
kofifus

Reputation: 19305

None of the above answers worked for me, the modal kept disappearing and I ended up with a brute force approach which is ugly and inefficient but works !

$('body').on('touchstart touchmove touchend', e => {
    let scrollDisabled=$('.scroll-disable');
    if (scrollDisabled.length > 0 &&  scrollDisabled.has($(e.target)).length===0) {
        e.preventDefault(); 
        e.stopPropagation();
    }
});
setInterval(() => $('.modal:visible').css('top', '20px'), 100);

$(document).on({
    'show.bs.modal': e => $(e.target).addClass('scroll-disable'),
    'hidden.bs.modal': e => $(e.target).removeClass('scroll-disable')
}, '.modal');

Upvotes: 0

Klaas van der Weij
Klaas van der Weij

Reputation: 1114

I've taken the solutions of @Aditya Prasanthi and @JIm, since one fixes the background-scrolling and the other fixes the skip-to-the-top after closing the modal, and turned them into one bare-minimum JS script:

let previousScrollY = 0;

$(document).on('show.bs.modal', () => {
    previousScrollY = window.scrollY;
    $('html').addClass('modal-open').css({
        marginTop: -previousScrollY,
        overflow: 'hidden',
        left: 0,
        right: 0,
        top: 0,
        bottom: 0,
        position: 'fixed',
    });
}).on('hidden.bs.modal', () => {
    $('html').removeClass('modal-open').css({
        marginTop: 0,
        overflow: 'visible',
        left: 'auto',
        right: 'auto',
        top: 'auto',
        bottom: 'auto',
        position: 'static',
    });
    window.scrollTo(0, previousScrollY);
});

It's, of course, possible and even adviced to use a class to set and unset the CSS for the body, however, I choose this solution to resolve a problem just in one place (and not require external CSS as well).

Upvotes: 26

JIm
JIm

Reputation: 97

My solution:

scrollPos = window.scrollY  - get current scroll position.

body { position: fixed;
   margin-top: -**scrollPos** px);

}

Then modal is closed:

body {position: "";
  margin-top: "";

}

and return scroll position to point before opened modal window:

window.scrollTo(0, scrollPos);

Upvotes: 1

Aditya Prasanthi
Aditya Prasanthi

Reputation: 109

refer to Does overflow:hidden applied to <body> work on iPhone Safari?

Added .freezePage to html and body when modal is showing

$('.modal').on('shown.bs.modal', function (e) {
  $('html').addClass('freezePage'); 
  $('body').addClass('freezePage');
});
$('.modal').on('hidden.bs.modal', function (e) {
  $('html').removeClass('freezePage');
  $('body').removeClass('freezePage');
});

the CSS

.freezePage{
  overflow: hidden;
  height: 100%;
  position: relative;
}

Upvotes: 10

Related Questions