Twitter Bootstrap modal opening/closing causes fix

2020-04-02 07:23发布

问题:

I am almost done with a simple 2-page website for my registered domain names. Unfortunately I have one small issue I can't seem to fix: a jumpy header when a Twitter Bootstrap modal opens and closes. On mobile devices there's no problem. The problem only occurs in larger viewports like desktops and laptops.

How to recreate

  1. Open http://www.domains.cloudlabz.nl/domains in a webbrowser and make sure you get a vertical scrollbar by lowering the viewport height.
  2. Click on one of the blue 'more info' buttons.
  3. Notice the jumping header and disappearing scrollbar once the modal opens.
  4. Close the modal and notice the header jumping back and the scrollbar reappearing.

Check the following image (same result in Opera, Safari, Firefox and Chrome):

What I'd like

I'd like the header to stop jumping when opening/closing a modal. The fact the scrollbar disappears is not an issue. Actually, I would like it to stay like that.

Update

I noticed the jumping header only occurs with fixed position elements such as my header (added Bootstrap class navbar-fixed-top). It even occurs on the Bootstrap website itself: http://getbootstrap.com/javascripts. Go to the 'Modals > Optional Sizes' area on a desktop and click one of the buttons. You'll see the right side menu jumping back and forth.

When the modal opens, the class .modal-open is added to the body element (thanks for pointing that out @Pred). It adds a padding of 15px to the right, which is the same width as the scrollbar gutter. This prevents the body from jumping back and forth.

Unfortunately this padding apparently does not apply to fixed elements.

回答1:

Bootstrap adds class="modal-open" and padding-right: 15px; to body when the modal is shown. To remove the right shift and keep the scroll bar add this to your css:

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

Tried in bootstrap 3.3.4



回答2:

I seemed to have found a quick fix for my issue. It uses a piece of javascript to add extra style to the header (15px padding-right) to prevent it from jumping. This might not be the best solution but for now it works just fine.

Since there were no issues on viewports smaller than 768px (mobile) this piece of code only adds the extra 15px to larger viewports such as desktops and laptops

<script>

    $(document).ready(function(){

        // Dirty fix for jumping scrollbar when modal opens

        $('#requestModal').on('show.bs.modal', function (e) {
            if ($(window).width() > 768) {
                $(".navbar-default").css("padding-right","15px");
            }
        });

        $('#requestModal').on('hide.bs.modal', function (e) {
            if ($(window).width() > 768) {
                $(".navbar-default").css("padding-right","0px");
            }
        });

    });

</script>

If you know a better solution (preferably CSS3 only), please let me know. Thanks for all the help!



回答3:

When the modal opens, the "modal-open" class is added to the HTML <body> element which hides overflow. You can change this by over-writing the "modal-open" class with overflow: inherit. This will keep the scrollbar in view, just as it is when the modal is closed. Keep in mind that this will change the overflow option whenever any modal is opened on the page. Hope this helps. Good luck!



回答4:

All this happens because of this part of code in bootstrap.js:

Modal.prototype.setScrollbar = function () {
    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
    if (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
}

That annoying problem happens in Firefox 32.0 (Gecko/20100101) and Chromium Version 37.0.2062.94 (Webkit 537.36) (Ubuntu 14.04). Not happens in QupZilla Version 1.6.6 (WebKit 537.21).

For me, the dirty fix is to comment the conditional line, after that it works in all browsers I tested (including some android's browsers).

NOTE: if you comment that line, you should be careful with the size of your modals since bootstrap will not create enough space for the new scrollbar.

Regards.



回答5:

As you usually put Bootstrap navbar as a direct child of the body container:

<body>
  <nav class="navbar navbar-fixed-top">...</nav>
</body>

You can use the body padding-right value, calculated in the Bootstrap core code to prevent it from "jumping" when opening a modal window, to fix the navbar issue as well . A pure CSS solution is below:

.navbar-fixed-top {
  padding-right: inherit;
}

Easy as that.



回答6:

This one only works if you know your page content is longer than the viewport (so any long scrolling page). You can just add the following to your CSS -

html {
  overflow-y: scroll;
}

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


回答7:

Another solution is to add:

.modal-open .navbar-fixed-top {
  overflow-y: scroll;
}

to prevent its content from jumping. Again, easy as that.



回答8:

I came around same issue and I solved it as follows

just add

body.modal-open {
  position: fixed;
  overflow: scroll;
  width: 100%;
  padding-right: 0!important;
}


回答9:

I manually change bootstap.js:

before change

Modal.prototype.setScrollbar = function () {
    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
  }

  Modal.prototype.resetScrollbar = function () {
    this.$body.css('padding-right', '')
  }

after change:

  Modal.prototype.setScrollbar = function () {
    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
    var headerPad = parseInt(($('.navbar-fixed-top').css('padding-right') || 0), 10)
    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
    if (this.bodyIsOverflowing) $('.navbar-fixed-top').css('padding-right', headerPad + this.scrollbarWidth)
  }

  Modal.prototype.resetScrollbar = function () {
    this.$body.css('padding-right', '')
    $('.navbar-fixed-top').css('padding-right', '')
  }


回答10:

I have a structure:

<html>
<body>
  <nav class="navbar navbar-fixed-top">...</nav>
  <section>
    <div class="container">...</div>
  </section>
  <section>
    <div class="container">...</div>
  </section>
  <footer>...</foter>
</body>
</html>

I'm using this CSS:

body.modal-open {padding-right: 0 !important}
body.modal-open nav,
body.modal-open section,
body.modal-open footer {padding-right: 17px !important}


回答11:

Add the following to your CSS:

body {
  overflow: inherit;
  padding-right: 0 !important;
}


回答12:

For Bootstrap 4 sticky-top, use the following snippet. Tested all the CSS solutions on this page but none worked for Bootstrap 4.

<script type="text/javascript">

    $('body').on('show.bs.modal', function () {
        $('.sticky-top').css('margin-left', '-=0px');
    });

    $('body').on('hidden.bs.modal', function () {
        $('.sticky-top').css('margin-left', 'auto');
    });

</script>

My page design was as follows

<header class="container">
    <div class="row">

    </div>
</header>

<div class="container sticky-top">
    <nav class="navbar navbar-expand-lg">
        This div jumped/shifted 17px to the right when opening a modal
    </nav>
</div>


回答13:

In my case, it can be solved by adding comments or remove these two lines right: 0; and left: 0; in bootstrap.css file:

.navbar-fixed-top,
.navbar-fixed-bottom {
  position: fixed;
  /* right: 0;
  left: 0; */
  z-index: 1030;
}

Note: I use bootstrap v3.3.7