twbs / bootstrap

The most popular HTML, CSS, and JavaScript framework for developing responsive, mobile first projects on the web.
https://getbootstrap.com
MIT License
170.55k stars 78.85k forks source link

Open modal is shifting fixed navbar to the right #14040

Closed mhawk0 closed 8 years ago

mhawk0 commented 10 years ago

re: https://github.com/twbs/bootstrap/issues/9855 in 3.2.0, when body has a scrollbar, it's content now stays in place when modal is opened (padding is added to the body). But fixed top navbar, having position: fixed, left: 0 and right: 0, now jumps to the right when modal is opened, as it ignores padding-right on the body.

cvrebert commented 10 years ago

What OS and browser are you using? Could you please make a JS Bin demonstrating the problem?

mdo commented 10 years ago

Confirmed in latest Safari and Chrome on OS X.

WeaselScience commented 10 years ago

Confirmed in latest Chrome on Windows 7

Vivi-wu commented 10 years ago

I come across another problem, also in 3.2.0 and the body has a scrollbar, different thing is my site header with class .navbar.navbar-default (so its position is relative not fixed) Open a small modal will make the navbar show 15px blank space to the right border of browser. selection_007

Browser : Chromium Version 34.0.1847.116 Ubuntu 14.04 The content stays in place (no shifting), so if you don't look at the top right corner, you won't notice this problem.

You can observer the problem on the bootstrap page in the section Modal/Optional sizes with the small modal example. http://getbootstrap.com/javascript/#modals-sizes selection_012

parminderkaur commented 10 years ago

This fixes it in version 3.2.0 :+1: .modal-open .navbar-fixed-top, .modal-open .navbar-fixed-bottom { padding-right: 17px; }

cvrebert commented 10 years ago

@parminderkaur Except that hardcodes the width of the scrollbar

nhouse commented 10 years ago

I am having this issue as well, but the problem changes slightly depending on whether a scrollbar is active.

When there IS a scrollbar, opening a modal causes the fixed navbar to shift to the right.

When there is NOT a scrollbar, opening a modal causes the page body to shift to the left.

Demo video: http://screencast.com/t/2PV8Y1IN7

Demo page: http://www.pricewombat.com/p/105797/Crest-3D-White-Whitestrips-Professional-Effects-Teeth-Whitening-Kit-20-Treatments-Packaging-May-Vary-

I'm running Chrome 36.0.1985.125 on Windows 7. Also tested in IE 11 and same thing happens.

ramon18 commented 10 years ago

My fix (in a custom js file, no need to patch current 3.3.4 BS sources)

    // TODO: Add any custom classes with 'position: fixed' to the selector below
    var fixedCls = '.navbar-fixed-top,.navbar-fixed-bottom';
    var oldSSB = $.fn.modal.Constructor.prototype.setScrollbar;
    $.fn.modal.Constructor.prototype.setScrollbar = function () {
        oldSSB.apply(this);
        if (this.bodyIsOverflowing && this.scrollbarWidth)
            $(fixedCls).css('padding-right', this.scrollbarWidth);
    }

    var oldRSB = $.fn.modal.Constructor.prototype.resetScrollbar;
    $.fn.modal.Constructor.prototype.resetScrollbar = function () {
        oldRSB.apply(this);
        $(fixedCls).css('padding-right', '');
    }

Dont forget to apply the same for the .navbar-fixed-bottom element any position: fixed

john-999 commented 10 years ago

Confirmed with:

Bootstrap 3.2.0
Firefox 32.0 (Linux)

(I can also confirm @nhouse's description.)

cvrebert commented 10 years ago

Thanks folks, we have sufficient confirmations; no need for further ones.

sanjay900 commented 10 years ago

I have a slightly different fix, the previous one didn't work:

$(document.body)
.on('show.bs.modal', function () {
    if (this.clientHeight <= window.innerHeight) {
        return;
    }
    // Get scrollbar width
    var scrollbarWidth = getScrollBarWidth()
    if (scrollbarWidth) {
        $('.navbar-fixed-top').css('margin-right', scrollbarWidth);    
    }
})
.on('hide.bs.modal', function () {
    $('.navbar-fixed-top').css('margin-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);
};
hzulla commented 10 years ago

No fix, just a bit of debugging, using Firefox 32.0.3 and Chromium 37.0.2062.120 on Ubuntu here.

After testing, I found that the vertical scrollbar for both browsers is 15px wide, but Modal.prototype.setScrollbar sets a value of 30px for padding-right instead. 15px would be correct.

The reason is that bodyPad = this.$body.css('padding-right') is 15px, which is then added to the 15px value of this.scrollbarWidth.

(I'm fairly new to this, so) I have no idea where that 15px value for padding-right comes from in this.$body.css. Firebug doesn't show me any such css setting for padding-right in the body tag.

tobyee commented 10 years ago

@ramon18 Thanks, the patch work for me.

martinsifra commented 9 years ago

Having still this problem with Chrome 38.0.2125.122. After open a modal, the a fixed navbar is shifted to the right.

cvrebert commented 9 years ago

No further confirmations are necessary.

The Bootstrap Team is fully aware that this is a legit bug.

g0aheadrlz commented 9 years ago

Thanks @parminderkaur , it works ;-)

restran commented 9 years ago

@parminderkaur

This fixes for me in version 3.2.0

.modal-open[style="padding-right: 17px;"] .navbar-fixed-top, .modal-open[style="padding-right: 17px;"] .navbar-fixed-bottom { padding-right: 17px; }

M1chae1 commented 9 years ago

@parminderkaur Thanks! The fix works on 3.3.2 too!

Hint-ru commented 9 years ago

@ramon18 Thx. But we should check this.bodyIsOverflowing too. if (this.bodyIsOverflowing && this.scrollbarWidth) $('.navbar-fixed-top').css('padding-right', this.scrollbarWidth);

JiNexus commented 9 years ago

I'm still experiencing this kind of bug in Bootstrap v3.3.4 I hope they will fix this issue. I tried putting padding-right: 17px on the fixed navbar to temporarily fix it but I found out that it only works on Chrome and Firefox using windows OS but when I switch to Ubuntu OS the value of padding-right in the body when modal is opened is changed to 15px, so that means that I have to change the value that I set in fixed navbar from 17px to 15px just to fix it on Chrome and Firefox in Ubuntu platform.

scooterlord commented 9 years ago

Hello.

After putting up with this for a couple of years and using hacks, shivs and useless javascripts, here I come with a pure css solution to the problem. Simple as hell. Cross-browser.

We create a class (eg no-jump), and apply it to all direct descendands of body and fixed elements.

Then simply:

.modal-open .no-jump { overflow-y:scroll; }

Since the body overflow is hidden and usually fixed elements are either at top or bottom and noone would scroll there, noone will ever notice it in any browser.

It's cross-browser, which means it doesn't need to detect scrollbar width which is different among different browsers/OS'es, OR detect touchscreens that have no scrollbars at all. Overflow-y will create the appropriate width of scrollbar according to each occasion.

I am surprised no-one came up with this solution so far (including myself).

ramon18 commented 9 years ago

@Hint-ru Ya the user may resize the window between modals, that's a nice fix, thanks :+1:

(I updated the code in my above post for copy/paste gurus)

JiNexus commented 9 years ago

Thanks @ramon18 and @Hint-ru you did great fixing with this kind of issue.

nozpheratu commented 9 years ago

@Hint-ru @JiNexus @ramon18 Unfortunately that won't work on different browsers / operating systems as scrollbars won't always have a pixel width of 17px. For instance, it's only 15 on Ubuntu Firefox.

JiNexus commented 9 years ago

Actually I tried it on Windows and Ubuntu, both Firefox and Chrome. They work to me perfectly fine. I don't know with Mac or any other browser such as Opera.

nozpheratu commented 9 years ago

@JiNexus Just saying, if I was your user and I went to your website right now using those snippets your website would still have the problem for me. It might work on some browsers/OSs, but it's no silver bullet.

JiNexus commented 9 years ago

@nozpheratu if you saw my previous post I already told that kind of problem that in different OS's the pixel is not always 17px. By the way have you seen the code that we are using? If you notice we are not defining a value to the padding-right, we let Javascript define the value by using "scrollbarWidth" so that it will be flexible to other OS's or browsers. Please review the code before jumping out to conclusions.

nozpheratu commented 9 years ago

@JiNexus I actually cc'd the wrong person, I meant to direct that original post to @restran.

JiNexus commented 9 years ago

@nozpheratu Seriously? you accidentally cc'd 3 wrong person from your original post? Anyway it doesn't matter, this case is close I hope bootstrap will add this fix to their next update.

nhouse commented 9 years ago

This issue is a continuation of https://github.com/twbs/bootstrap/issues/9855 which was opened about a year and a half ago. Considering the number of websites using Bootstrap and affected by this probem, I'm astounded it hasn't been fixed yet.

JiNexus commented 9 years ago

I don't recommend those css hacks that puts overflow: y-scroll, lets say for example your modal has a heap of content on it that means you wont be able to scroll down your modal anymore. For me the right fixed is this, you allow Javascript to determine its scrollbarWidth and put it as your padding-right and as the modal closes you also reset the padding-right by removing the css: (Credit to @ramon18 )

/* File: fixed.js
 * Fix shifting fixed navbar to the right 
 */

    $(document).ready(function(){
        $(window).load(function(){
            var oldSSB = $.fn.modal.Constructor.prototype.setScrollbar;
            $.fn.modal.Constructor.prototype.setScrollbar = function () 
            {
                oldSSB.apply(this);
                if(this.bodyIsOverflowing && this.scrollbarWidth) 
                {
                    $('.navbar-fixed-top, .navbar-fixed-bottom').css('padding-right', this.scrollbarWidth);
                }       
            }

            var oldRSB = $.fn.modal.Constructor.prototype.resetScrollbar;
            $.fn.modal.Constructor.prototype.resetScrollbar = function () 
            {
                oldRSB.apply(this);
                $('.navbar-fixed-top, .navbar-fixed-bottom').css('padding-right', '');
            }
        });
    });
empz commented 9 years ago

@scooterlord Can you provide a full example? I've added your CSS class and applied it to my nav element which is the only fixed element but it's still shifting when the modal is opened...

nhouse commented 9 years ago

@JiNexus's code worked great for me.

sarahmurray commented 9 years ago

A similar issue occurs when immediately opening a modal from another modal (using "show" and "hide" methods) – the padding and .modal-open class are removed from the body but not re-added, until the second modal is dismissed, when the padding is then added to the body. And if you go through the loop a few times it keeps adding more and more padding to the body.

Or is opening a modal from another modal not supported?

ramon18 commented 9 years ago

Overlapping Modals is not supported See http://getbootstrap.com/javascript/#modals

JiNexus commented 9 years ago

@sarahmurray I suggest you try to use the event handling in bootstrap http://getbootstrap.com/javascript/#modals-events, like for example hidden.bs.modal - This event is fired when the modal has finished being hidden from the user (will wait for CSS transitions to complete).

In my sample code below, My #dangerModal won't show until the #loadingModal is hidden. Please always use $(document).ready(function(){ .. }); and $(window).load(function(){ .. }); this is to ensure that all js are loaded.

$(document).ready(function(){
    $(window).load(function(){
        $(function(){
            $('#loadingModal').on('hidden.bs.modal', function (e) {
                $('#dangerModal').modal({show: true,
                                         keyboard: false,
                                         backdrop: 'static'});
            });
        });
    });
});
eLement87 commented 9 years ago

I had the same issues and no solutions above worked for me.

But this piece of code worked for me to fix the 15px bar on the right side :

body {
    padding-right: 0 !important;
}

But the Main-Nav is still jiggeling, when the Modal is comming up. And then...

#main-nav {
    padding-right: 0 !important;
}

And it's gone :)

Bootstrap 3.3.4

unholyknight commented 9 years ago

@eLement87 Those definitions look like they work without any unintended consequences as far as I've noticed. Thanks!

blackfyre commented 9 years ago

:+1: For @eLement87's solution, and @unholyknight's observations

silvenon commented 9 years ago

@JiNexus' solution is adding padding to avoid shifting to the right, it works well. I don't see how the solution above could possibly work as it brings everything, including Bootstrap's own patches, back to square zero, negating that the issue even exists. Am I missing something? Are you sure you were testing in environments where scrollbars take up actual space?

ryoga7482 commented 9 years ago
body.modal-open {
overflow-y: scroll;
padding-right: 0 !important;
}

Worked in my situation - combination of this and #9855

@schack86 :


.modal {
margin-left: 17px;
}

Shifts modal if centering is offset.

fxrising commented 9 years ago

Thanks ryoga7482, that was the only css solution that worked for me :)

nairys commented 9 years ago

@ryoga7482 worked for me. thanks!

JosKrause commented 9 years ago

Also would like to add that @ryoga7482 solution worked absolutely flawless so far in all of my pages dealing with modals, also when the content is a centered container; applied to BS 3.3.0.

schack86 commented 9 years ago

Hi guys. I'm new on this forum, but I'm experiencing the same problem with bootstrap 3.3.5. Implementing this solution: body.modal-open { overflow-y: scroll; padding-right: 0 !important; } fixes the issue of added padding to body perfectly. But my modal isn't horizontally centered anymore. It's moved to the left by amount of the width of the scrollbar (in my case: padding-right: 17px;) Do any of you brainiacs know how to fix it?

JiNexus commented 9 years ago

@schack86 try our code above. I assure it work perfectly fine in different browser and OS.

schack86 commented 9 years ago

@JiNexus I've tried your code in win7 chrome and firefox, and so far it works like a charm. I have yet to try it on ios.

JiNexus commented 9 years ago

@schack86, I've been there in your situation. We are glad that it fixes your problem. I don't want to argue with the other fixes above since only those who does a split testing with different browser with different OS's will truly understand which one is the right fix for them.

schack86 commented 9 years ago

@JiNexus Am I missing something. The fixed top nav still works perfectly. But if the modal is shorter than the viewport and scrollbar isn't needed, then the padding on different elements still occur. Do I have to include these elements somehow in the script? Please help.

I simply don't understand why this issue haven't been solved by the bootstrap team yet. So frustrating! scrollbar noscrollbar

JiNexus commented 9 years ago

@schack86, Hey, I reviewed my code and my modal, I also tried to lessen the contents of my modal to make it shorter in the screen and see if I will experience the same issue that you are talking about but so far it is working fine on my end. Can you try to clean the css fixed that you have made before you use our code to fix the problem with modal? It might be the culprit. For clarification I'm currently using Bootstrap v3.3.4. Cheers!