uiv-lib/uiv

Scrollbar padding is not placed on .navbar-fixed-top, .navbar-fixed-bottom when opening Modal.

Closed this issue · 6 comments

Describe the bug
If the <body> element contains a navbar (.navbar-fixed-top or .navbar-fixed-bottom) and the <body> has a fixed scrollbar (overflow-y: scroll), then when opening a UIV Modal, the navbar content moves to the right instead of staying in its fixed position.

To Reproduce
Steps to reproduce the behavior:

  1. Create a body element with a FIXED navbar inside (.navbar-fixed-top or .navbar-fixed-bottom), possibly using UIV's <Navbar>.
  2. Add overflow-y: scroll CSS to the <body> element.
  3. Add a <Modal> UIV element to the <body>
  4. Open the modal.

Expected behavior
The navbar should not move. Instead, an amount of padding-right equal to the scrollbar width should be placed on the .navbar-fixed-top or .navbar-fixed-bottom after the <body>'s scrollbar is taken away (taken away via class .modal-open).

UIV is already adding a padding-right of the scrollbar width to the <body> element when opening the modal in its toggleBodyOverflow method:

export function toggleBodyOverflow (enable) {
  const MODAL_OPEN = 'modal-open'
  const body = document.body
  if (enable) {
    removeClass(body, MODAL_OPEN)
    body.style.paddingRight = null
  } else {
    const browsersWithFloatingScrollbar = isIE10() || isIE11()
    const documentHasScrollbar = hasScrollbar(document.documentElement) || hasScrollbar(document.body)
    if (documentHasScrollbar && !browsersWithFloatingScrollbar) {
      body.style.paddingRight = `${getScrollbarWidth()}px`
    }
    addClass(body, MODAL_OPEN)
  }
}

however the same is not done for the .navbar-fixed-top and .navbar-fixed-bottom. This is in contrast to Bootstrap's own bootstrap.js, which does specifically target .navbar-fixed-top and .navbar-fixed-bottom for padding corrections when opening modals.

It would be appreciated if the same padding-right correction logic could be done for fixed navbars, similar to bootstrap.js.

Screenshots

Before modal open (blue part is navbar-fixed-top):

image

After modal open:

image

It is a little jarring when a navbar with a lot of content moves when opening and closing a modal.

Additional context

UIV version is 0.36.1, although looking at github I think this would still be a problem in the latest.

Would very much appreciate a 0.X fix as I have not upgraded to 1.X just yet.

wxsms commented

Looks like the original jQuery version of Bootstrap does not add padding to navbar-fixed-*, too:

image

You can workarround this by adding such css to your project:

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

I don't know if I should add the additional logics to toggleBodyOverflow, because somebody might not want this behaviour.

Hi @wxsms

Can you please double verify your example used the bootstrap.js modal implementation and not the UIV implementation of modal. Also verify you are not using a browser with a zero-width scrollbar (such as IE10 or IE11).

I have verified that the Bootstrap 3.4.1's bootstrap.js implementation does add padding to the navbar. See my example below, which is a modal produced by bootstrap.js and not UIV. As you can see the .navbar-fixed-top element is given a padding-right equal to the scrollbar.

image

There is code in Bootstrap 3.4.1 's bootstrap.js which is checking for .navbar-fixed-top & .navbar-fixed-bottom and gives them padding equal to the scrollbar width when the modal opens:

var Modal = function (element, options) {
    ...
    this.fixedContent = '.navbar-fixed-top, .navbar-fixed-bottom'
    ...

   }

 Modal.prototype.show = function (_relatedTarget) {
    ...
    this.setScrollbar()
    this.$body.addClass('modal-open')
    ...

}

Modal.prototype.setScrollbar = function () {
    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
    this.originalBodyPad = document.body.style.paddingRight || ''
    var scrollbarWidth = this.scrollbarWidth
    if (this.bodyIsOverflowing) {
      this.$body.css('padding-right', bodyPad + scrollbarWidth)
      $(this.fixedContent).each(function (index, element) {
        var actualPadding = element.style.paddingRight
        var calculatedPadding = $(element).css('padding-right')
        $(element)
          .data('padding-right', actualPadding)
          .css('padding-right', parseFloat(calculatedPadding) + scrollbarWidth + 'px')
      })
    }
  }

Unfortunately I tried a fixed-padding CSS solution with .modal-open. However it doesn't work on IE, as you know IE has zero-width scrollbars which means this padding shouldn't be applied in that scenario. There are possibly other browser versions which do or do not used a 15px-width scrollbar. Ultimately I concluded the cross-browser solution would be to measure the scrollbar width with JS on modal open - which at that point I found Bootstrap was already doing that.

wxsms commented

I see. will work on it soon.

wxsms commented

pls try v1.1.1

@wxsms Have just upgraded and tried it in Chrome/IE/Firefox and it works well. The navbar does not move when opening a modal.

Thank you for your quick response and continued support for the UIV library.

wxsms commented

@StefanCardnell welcome. pls give this project a star if you found it helpful.