Twitter Bootstrap modal pushes html content to the

2019-01-21 12:21发布

问题:

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

回答1:

For bootstrap 3.x.x.

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

The trick is, 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 test 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 issues I could find with IE:

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

Care about position:fixed!

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

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

alternative with wrapper

If you do not like set overflow:hidden on html (some people don´t want this, but it works, is valid and 100% standard compliant), you can wrap the content of body in an extra div.

Than you do not need extra care for fixed elements, you can use it like before.

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:

  • #12627
  • #9855

Update 2: FYI

In Bootstrap 3.2.0 they add a workaround to modal.js that try 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 ca. 20% of code from modal.js only try to handle that issues.



回答2:

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 */
}


回答3:

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



回答4:

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;
}


回答5:

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.



回答6:

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.



回答7:

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 .



回答8:

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;
}


回答9:

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



回答10:

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



回答11:

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;
}


回答12:

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;
}


回答13:

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



回答14:

Just do this simply and thats all

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

Works for me. Short and does the job.



回答15:

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



回答16:

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;
}


回答17:

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..



回答18:

Simply add a class

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

it worked for me



回答19:

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.



回答20:

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;
}


回答21:

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;}


回答22:

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/



回答23:

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.



回答24:

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);
};


回答25:

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;
}


回答26:

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

and remove 4 function from bootstrap.js -

 checkScrollbar
 setScrollbar
 resetScrollbar
 measureScrollbar


回答27:

For me it works fine like this

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


回答28:

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

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


回答29:

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

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


回答30:

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!