Question

If I open a modal dialog, through Twitter Bootstrap, I've noticed that it pushes all the html content of the page (i.e., in the container) to the left a little bit, and then puts it back to normal after closing itself. However, this only happens if the browser width is large enough to not be on the "mobile" (i.e., smallest) media query. This occurs with the latest versions of FF and Chrome (haven't tested other browsers).

You can see the problem here: http://jsfiddle.net/jxX6A/2/

Note: You have to increase the width of the "Result" window so it switches to the "med" or "large" media query css.

I have setup the HTML of the page based upon the examples shown on Bootstrap's site:

<div class='container'>
    <div class='page-header'>
        <h4>My Heading</h4>
    </div>
    <div id='content'>
        This is some content.
    </div>
    <div class='footer'>
        <p>&copy; 2013, me</p>
    </div>
</div>

I'm guessing this is not supposed to happen, but I'm not sure what I've done wrong.

EDIT: This is a known bug, for more (and up-to-date) information, please see: https://github.com/twbs/bootstrap/issues/9855

Was it helpful?

Solution

For bootstrap 3.x.x.

I have found a solution, that works with 100% CSS and no JavaScript.

The trick is to show the scrollbar for modal over the scrollbar of html content.

CSS:

html {
  overflow: hidden;
  height: 100%;
}
body {
  overflow: auto;
  height: 100%;
}

/* unset bs3 setting */
.modal-open {
 overflow: auto; 
}

Here is an online example: http://jsbin.com/oHiPIJi/43/

I tested it on Windows 7 with:

  • FireFox 27.0
  • Chrome 32.0.1700.107 m
  • IE 11 in Browser Mode 8, 9, 10, Edge (Desktop)
  • IE 11 in Browser Mode 8, 9, 10, Edge (windows phone)

One new little issue I found with IE:

IE has background (=body) scrolling with mouse wheel, if there is nothing more to scroll in the foreground.

Take care with position:fixed!

Because of the nature of this workaround, you need extra care for fixed elements. For example the padding for "navbar fixed" needs to be set to html and not to body (how it is described in bootstrap doc).

/* only for fixed navbar: 
* extra padding setting not on "body" (like it is described in docs), 
* but on "html" element
* the value used depends on the height of your navbar
*/
html {
  padding-top: 50px;
  padding-bottom: 50px;
}

Alternative with wrapper

If you do not like setting overflow:hidden on html (some people don't like this, but it works, is valid and 100% standards compliant), you can wrap the content of body in an extra div. You can use it as before by using this approach.

body, html {
  height: 100%;
}
.bodywrapper {
  overflow: auto;
  height: 100%;
}

/* unset bs3 setting */
.modal-open {
 overflow: auto; 
}

/* extra stetting for fixed navbar, see bs3 doc
*/
body {
  padding-top: 50px;
  padding-bottom: 50px;
}

Here is an example: http://jsbin.com/oHiPIJi/47/

Update:

Issues in Bootstrap:

Update 2: FYI

In Bootstrap 3.2.0 they add a workaround to modal.js that tries to handle the issues with Javascript for every invoke of modal.prototype.show(), Modal.prototype.hide() and Modal.prototype.resize(). They add 7 (!) new methods for that. Now about 20% of code from modal.js tries to handle just that issue.

OTHER TIPS

Try this:

body.modal-open {
    overflow: auto;
}
body.modal-open[style] {
    padding-right: 0px !important;
}

.modal::-webkit-scrollbar {
    width: 0 !important; /*removes the scrollbar but still scrollable*/
    /* reference: http://stackoverflow.com/a/26500272/2259400 */
}

It is actually caused by the following rule in bootstrap.css:

body.modal-open,
.modal-open .navbar-fixed-top,
.modal-open .navbar-fixed-bottom {
  margin-right: 15px;
}

I am not exactly sure why it behaves like that (perhaps to account for scrollbar somehow) but you can change the behaviour with this:

body.modal-open {margin-right: 0px}

EDIT: Actually, this is a reported issue in bootstrap: https://github.com/twbs/bootstrap/issues/9855

When the model opens, a padding of 17px to the right of the body. The code below should resolve that issue.

body {
padding-right: 0px !important;
}

Here's the fix proposed by user yshing that really FIXED it for me while using Bootstrap v3.1.1 and Google Chrome 35.0.1916.114m. The fix comes from a GitHub issue thread regarding this matter:

.modal
{
    overflow-y: auto;
}

.modal-open
{
   overflow:auto;
   overflow-x:hidden;
}

The fix will land only in Bootstrap 3.2 as desbribed by mdo.

To prevent the page from shifting in similar instances - for example an accordion opening that goes past the bottom of the page - I add this in CSS:

body {
    overflow-y: scroll;
    height: 100%;
}

The overflow-y: scroll forces the scrollbar to present at all times. To be honest, I can't remember why I put height:100% in there... but you don't seem to require it for this problem.

Demo: http://jsfiddle.net/jxX6A/8/

There is still a little movement. But that seems to be present on Bootstrap's own example page: http://getbootstrap.com/javascript/#modals

So I'm guessing you're stuck with it... but it's still far better than what you were seeing initially.

EDIT: I might be concerned that adding these styles would interfere with other Bootstrap stuff, as I haven't used it myself, so you might want to double check on that.

You just edit .modal-open class form bootstrap.min.css file, I thin it's will be ok .modal-open{overflow:auto}

The over-flow:hidden is set there , you just set over-flow:auto .

i have faced same problem and following solution

.modal-open {
    overflow: visible;
}

.modal-open, .modal-open .navbar-fixed-top, .modal-open .navbar-fixed-bottom {
    padding-right:0px!important;
}

A lot has changed since bootstrap 3.3.6 so the solutions above may not suffice.

To solve this, look at the setScrollbar function in bootstrap.js (or bootstrap-min.js of course), you will immediately notice that bootstrap is adding padding-right to the body element setting its value to a worked out value of scrollbarWidth plus existing padding-right on the body (or 0 if not).

If you comment out the below

//this.$body.css('padding-right', bodyPad + this.scrollbarWidth)

In your css override bootstrap modal-open class with the below

.modal-open{
  overflow:inherit;
 }

Folks have suggested overflow-y: scroll; the problem with this is that your content shifts if scroll bar does not exists in the first place.

NB As per http://getbootstrap.com/javascript/#modals, always try to place a modal's HTML code in a top-level position in your document

I have same problem and I got solution that is work for me....

body .modal-open {
  padding-right: 0% !important;
  overflow-y: auto;
}

place this code at top of your style.css file

Found this answer in TB issues

just by adding this below css that small movement will be fixed

body, .navbar-fixed-top, .navbar-fixed-bottom {
  margin-right: 0 !important;
}

Credits to https://github.com/tvararu

I use Bootstrap v3.3.4 and see this problem, I understood that Bootstrap modal add 17px padding right to the body, so just simply use following code:

body {
    padding-right: 0 !important;
}

No solution here fixed my issue. But following Css I got from Github worked for me.

body.modal-open {
padding-right: 0px !important;
overflow-y: auto;
}

Just do this simply and thats all

.modal-open {
padding-right: 0 !important;
}

Works for me. Short and does the job.

This is a reported issue to bootstrap: https://github.com/twbs/bootstrap/issues/9855

And this is my temporary quick fix and it's work using fixed top navbar, only using javascript. Load this script along with your page.

$(document.body)
.on('show.bs.modal', function () {
    if (this.clientHeight <= window.innerHeight) {
        return;
    }
    // Get scrollbar width
    var scrollbarWidth = getScrollBarWidth()
    if (scrollbarWidth) {
        $(document.body).css('padding-right', scrollbarWidth);
        $('.navbar-fixed-top').css('padding-right', scrollbarWidth);    
    }
})
.on('hidden.bs.modal', function () {
    $(document.body).css('padding-right', 0);
    $('.navbar-fixed-top').css('padding-right', 0);
});

function getScrollBarWidth () {
    var inner = document.createElement('p');
    inner.style.width = "100%";
    inner.style.height = "200px";

    var outer = document.createElement('div');
    outer.style.position = "absolute";
    outer.style.top = "0px";
    outer.style.left = "0px";
    outer.style.visibility = "hidden";
    outer.style.width = "200px";
    outer.style.height = "150px";
    outer.style.overflow = "hidden";
    outer.appendChild (inner);

    document.body.appendChild (outer);
    var w1 = inner.offsetWidth;
    outer.style.overflow = 'scroll';
    var w2 = inner.offsetWidth;
    if (w1 == w2) w2 = outer.clientWidth;

    document.body.removeChild (outer);

    return (w1 - w2);
};

Here is the working example: http://jsbin.com/oHiPIJi/64

i have faced same problem and following solution works for me

.modal-open {
    overflow: visible;
}
.modal-open, .modal-open .navbar-fixed-top, .modal-open .navbar-fixed-bottom {
    padding-right:0px!important;
}

Try to change all occurence of below

$body.css('padding-right',XXX)

with

$body.css('padding-right'0)

on your bootstrap.js file.

That's All..

Simply add a class

.modal-open{ padding-right:0px !important;}

it worked for me

I fixed my problem and I think it will work for everyone. In bootstrap.js there's a line:

if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)

It means in some case Bootstrap will add a padding-right of scrollbar width while opening a modal. So @pmanOnu was half way right, but don't delete this whole line of code but only

replace bodyPad + this.scrollbarWidth in bootstrap.js with 0

to make Bootstrap adding a padding-right of 0px (which is the same of not adding).

Then add .modal-open {overflow: initial;} to your custom css to prevent Bootstrap from disabling scrollbar while opening modals.

If all the above solutions didn't work , it may be because of positioning the content ,Just take a look at the position of the modal

body.modal-open
{
   padding-right: 0 !important; // not important
   position: relative;
}

So it turns out I was actually getting right margin of 250px or so. My problem seemed to be that .modal-open was getting set to position: fixed, and that was the cause for whatever reason. So in my case, the fix was similar, but I set the position value to the default as below:

.modal-open{ position: initial !important;}

For anyone still struggling with this - the latest version of Bootstrap has a native fix. Just update the bootstrap.min.css and bootstrap.min.js files from the latest version.

http://getbootstrap.com/

I really didn't like any of the solutions provided, and used a combination of them (along with a fix I previously had for qTip modals) to come up with something that worked best for me with Bootstrap v3.3.7.

UPDATE: Resolved issue with fixed navbar positioning on iOS.

CSS:

/* fix issue with scrollbars and navbar fixed movement issue with bootstrap modals */
html {
    overflow-y: scroll !important;
}

html.noscroll {
    position: fixed;
    width: 100%;
    top:0;
    left: 0;
    height: 100%;
    overflow-y: scroll !important;
}

.modal-open .modal {
    padding-right: 0 !important;
}

.modal-open[style] {
    padding-right: 0px !important;
}

.modal::-webkit-scrollbar {
    width: 0 !important; /*removes the scrollbar but still scrollable*/
}
/* end modal fix */

JavaScript:

/* fix for modal overlay scrollbar issue */
$(document).ready(function() {
    var curScrollTop;
    var prevScrollTop;
    $('.modal').on('show.bs.modal', function() {
        curScrollTop = $(window).scrollTop();
        $('html').addClass('noscroll').css('top', '-' + curScrollTop + 'px');
        $('.navbar-fixed-top').css({'position':'absolute','top':curScrollTop});     
        $(window).on("resize", function() {             
            var bodyH = $("body").height();
            var winH = $(window).height();
            if (winH > bodyH) {
                prevScrollTop = curScrollTop;
                curScrollTop = 0;
                $('.navbar-fixed-top').css({'position':'absolute','top':'0'}); 
            }
            else {
                $('html').removeClass("noscroll");
                if (curScrollTop == 0) window.scrollTo(0, prevScrollTop);
                else window.scrollTo(0, curScrollTop);
                curScrollTop = $(window).scrollTop(); 
                $('.navbar-fixed-top').css({'position':'absolute','top':curScrollTop});  
                $('html').addClass("noscroll");
            }
            $('html').css('top', '-' + curScrollTop + 'px');
        })
    })
    $('.modal').on('hide.bs.modal', function() {
        $('html').removeClass("noscroll");
         $('.navbar-fixed-top').css({'position':'fixed','top':'0'});
        window.scrollTo(0, curScrollTop);
        $(window).off("resize");
    })
})

This allows the background to be "fixed" yet still allows the modals to be scrollable, resolves the issue of double scrollbar and the repositioning of the fixed navbar.

Note that there is additional code there as well to remember the 'scroll' position (and return to it) when the modal is closed.

Hope this helps anyone else looking to achieve what I was going after.

I found the answer by Agni Pradharma working for me; however not entirely in Chrome.

It appears the document scrollbar is wider than another elements scrollbar; so I edited the getScrollBarWidth function.

It simply first checks the width; removes the document scrollbar; then compares the difference. It also happens to be much less code.

$(document.body)
    .on('show.bs.modal', function () {
    if (this.clientHeight <= window.innerHeight) {
        return;
    }
    // Get scrollbar width
    var scrollbarWidth = getScrollBarWidth()
    if (scrollbarWidth) {
        $(document.body).css('padding-right', scrollbarWidth);
        $('.navbar-fixed-top').css('padding-right', scrollbarWidth);
    }
})
.on('hidden.bs.modal', function () {
    $(document.body).css('padding-right', 0);
    $('.navbar-fixed-top').css('padding-right', 0);
});

function getScrollBarWidth () {
    var fwidth = $(document).width();
    $('html').css('overflow-y', 'hidden');
    var swidth = $(document).width();
    $("html").css("overflow-y", "visible");
    return (swidth - fwidth);
};

Here's what I used, will work 100% in Bootstrap 3.2.0 as long as you don't mind forcing scrollbars.

.modal-open .modal {
  overflow-x: hidden;
  overflow-y: scroll;
}

the best way is: to add to BODY overflow-y: scroll

and remove 4 function from bootstrap.js -

 checkScrollbar
 setScrollbar
 resetScrollbar
 measureScrollbar

For me it works fine like this

 .modal-open .modal {
  overflow-x: scroll;
  overflow-y: scroll;
}

For me the following seems to work - tested in Firefox and Chrome on Linux:

body.modal-open {
    overflow: inherit;
    padding-right: inherit !important;
}

This worked for me. Overrides the 17px padding added to the right of the body:

body.modal-open {
    padding-right: inherit !important;
}

I tweaked this answer further up this thread by TBAG

body.modal-open { padding-right: 0px !important; overflow-y: auto; }

With a minor tweak it works on the desktop, for mobile devices overflow is set to hidden

final code

body.modal-open { padding-left: 16px!important; overflow-y: auto; }

Hope this helps!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top