Prevent BODY from scrolling when a modal is opened

Prevent BODY from scrolling when a modal is opened

I want my body to stop scrolling when using the mousewheel while the Modal (from http://twitter.github.com/bootstrap) on my website is opened.
I’ve tried to call the piece of javascript below when the modal is opened but without success
$(window).scroll(function() { return false; });

AND

$(window).live(‘scroll’, function() { return false; });

Please note our website dropped support for IE6, IE7+ needs to be compatible though.

Solutions/Answers:

Solution 1:

Bootstrap’s modal automatically adds the class modal-open to the body when a modal dialog is shown and removes it when the dialog is hidden. You can therefore add the following to your CSS:

body.modal-open {
    overflow: hidden;
}

You could argue that the above code belongs to the Bootstrap CSS code base, but this is an easy fix to add it to your site.

Update 8th feb, 2013
This has now stopped working in Twitter Boostrap v. 2.3.0 — they no longer add the modal-open class to the body.

A workaround would be to add the class to the body when the modal is about to be shown, and remove it when the modal is closed:

$("#myModal").on("show", function () {
  $("body").addClass("modal-open");
}).on("hidden", function () {
  $("body").removeClass("modal-open")
});

Update 11th march, 2013
Looks like the modal-open class will return in Bootstrap 3.0, explicitly for the purpose of preventing the scroll:

Reintroduces .modal-open on the body (so we can nuke the scroll there)

See this: https://github.com/twitter/bootstrap/pull/6342 – look at the Modal section.

Solution 2:

The accepted answer doesn’t work on mobile (iOS 7 w/ Safari 7, at least) and I don’t want MOAR JavaScript running on my site when CSS will do.

This CSS will prevent the background page from scrolling under the modal:

body.modal-open {
    overflow: hidden;
    position: fixed;
}

However, it also has a slight side-affect of essentially scrolling to the top. position:absolute resolves this but, re-introduces the ability to scroll on mobile.

If you know your viewport (my plugin for adding viewport to the <body>) you can just add a css toggle for the position.

body.modal-open {
    // block scroll for mobile;
    // causes underlying page to jump to top;
    // prevents scrolling on all screens
    overflow: hidden;
    position: fixed;
}
body.viewport-lg {
    // block scroll for desktop;
    // will not jump to top;
    // will not prevent scroll on mobile
    position: absolute; 
}

I also add this to prevent the underlying page from jumping left/right when showing/hiding modals.

body {
    // STOP MOVING AROUND!
    overflow-x: hidden;
    overflow-y: scroll !important;
}

this answer is a x-post.

Solution 3:

Simply hide the body overflow and it makes body not scrolling. When you hide the modal, revert it to automatic.

Here is the code:

$('#adminModal').modal().on('shown', function(){
    $('body').css('overflow', 'hidden');
}).on('hidden', function(){
    $('body').css('overflow', 'auto');
})

Solution 4:

You could try setting body size to window size with overflow: hidden when modal is open

Solution 5:

Warning: The option below is not relevant to Bootstrap v3.0.x, as scrolling in those versions has been explicitly confined to the modal itself. If you disable wheel events you may inadvertently prevent some users from viewing the content in modals that have heights greater than the viewport height.


Yet Another Option: Wheel Events

The scroll event is not cancelable. However it is possible to cancel the mousewheel and wheel events. The big caveat is that not all legacy browsers support them, Mozilla only recently adding support for the latter in Gecko 17.0. I don’t know the full spread, but IE6+ and Chrome do support them.

Here’s how to leverage them:

$('#myModal')
  .on('shown', function () {
    $('body').on('wheel.modal mousewheel.modal', function () {
      return false;
    });
  })
  .on('hidden', function () {
    $('body').off('wheel.modal mousewheel.modal');
  });

JSFiddle

Solution 6:

You need to go beyond @charlietfl’s answer and account for scrollbars, otherwise you may see a document reflow.

Opening the modal:

  1. Record the body width
  2. Set body overflow to hidden
  3. Explicitly set the body width to what it was in step 1.

    var $body = $(document.body);
    var oldWidth = $body.innerWidth();
    $body.css("overflow", "hidden");
    $body.width(oldWidth);
    

Closing the modal:

  1. Set body overflow to auto
  2. Set body width to auto

    var $body = $(document.body);
    $body.css("overflow", "auto");
    $body.width("auto");
    

Inspired by: http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php