Twitter Bootstrap modal pushes html content to the left

允我心安 提交于 2019-11-28 17:11:05

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:

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.

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

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

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

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

Zinnira Munir

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

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

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

and remove 4 function from bootstrap.js -

 checkScrollbar
 setScrollbar
 resetScrollbar
 measureScrollbar
Erduan

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

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!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!