Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

the background move a little when opening a modal. #2631

Closed
jixiangcn opened this issue Aug 26, 2014 · 37 comments
Closed

the background move a little when opening a modal. #2631

jixiangcn opened this issue Aug 26, 2014 · 37 comments

Comments

@jixiangcn
Copy link

when I click button to show a "modal", the background move a little then move back, which is not happened in bootstrap and uikit modal.

@jixiangcn
Copy link
Author

You can reproduce it open the following link in Chrome.
http://angular-ui.github.io/bootstrap/ modal part press any of the 3 buttons, when the modal is showing, notice the background content (not the modal) move to right a little bit.
In the uikit demo http://getuikit.com/docs/modal.html the modal opens smoothly, the background without any move.

@villelahdenvuo
Copy link

For more information about the issue: twbs/bootstrap#9855

It seems that someone has already ported the fix, but hasn't made a pull request MrOrz@1a4729a

@jixiangcn
Copy link
Author

👍

@villelahdenvuo
Copy link

@jixiangcn Why did you close the issue? I think it should be kept open until the fix has been ported to this library. I don't want to patch my own version of angular-bootstrap for this.

@jixiangcn jixiangcn reopened this Aug 26, 2014
@kgierke
Copy link

kgierke commented Sep 19, 2014

A solution for this problem would be to calculate the scrollbar width and append the result to the tag as negative margin left.

@chrisirhc
Copy link
Contributor

For reference, the original fix is at twbs/bootstrap@0907244 . PRs are are welcome.

@kashesandr
Copy link

Faced with the same issue.

@TilmannBach
Copy link

issue can be seen even on the bootstrap-ui documentation website

@Foxandxss
Copy link
Contributor

I am not able to reproduce it so I am not sure if this is stale or not. Please open an issue with a plunker if you think this is still an issue.

Thank you.

@j3ffb
Copy link

j3ffb commented Oct 23, 2015

@Foxandxss This is still an issue, as @TilmannBach says, you can see it on the doco website at https://angular-ui.github.io/bootstrap/#/modal but make sure you are using a browser that consumes a scrollbar width on the page, like FF or Chrome on Windows.

@Foxandxss
Copy link
Contributor

Ah, missed the windows part. I am using mac with this annoying scrollbars.

@Foxandxss Foxandxss reopened this Oct 23, 2015
@NoelKennedy
Copy link

I get the same effect on OS X with Chrome (46.0.2490.80 (64-bit)) & Firefox (41.0.2)

@j3ffb
Copy link

j3ffb commented Oct 23, 2015

@NoelKennedy this will depend on your settings in OSX. If scrollbar is visible on page load = you will see the bug

@TilmannBach
Copy link

Windows 10

  • Edge: Ok
  • IE 11: Ok
  • Chrome 46: Bugged

@NoelKennedy
Copy link

@j3ffb Confirmed; I can toggle the problem on and off via OS X settings. The screenshot is OS X settings (under General). With 'Show scroll bars' set to 'Automatically....' the problem occurs. If you set it to 'When scrolling' the problem does not occur.

screen shot 2015-10-23 at 16 47 09

@icfantv
Copy link
Contributor

icfantv commented Oct 28, 2015

I'm not sure there's anything we can do here.

@stefan-dimitrov
Copy link

Maybe this suggestion will help with the problem: http://stackoverflow.com/a/20564773/915372 ?

@prasadrajandran
Copy link

Hello,

I don't know if this is still an issue for everyone but this should (hopefully) fix it:

CSS:

html {
  overflow-y: scroll;
}

That forces the scroll bar to be displayed at all times regardless of whether it's actually needed or not.

@bboyle
Copy link

bboyle commented Feb 28, 2016

@prasadrajandran that does stop the content from shifting, but it means the body can be scrolled while the modal is open, which feels wrong. I think we're all after a solution that's the best of both worlds -- scrolling is disabled, and content does not shift sideways.

@bboyle
Copy link

bboyle commented Feb 28, 2016

here is how bootstrap are measuring scrollbars to handle this issue: https://github.com/twbs/bootstrap/blob/master/js/modal.js#L259

@prasadrajandran
Copy link

@bboyle, I didn't that doing that would allow the body to be scrolled while the modal is open. Interesting.

I'm probably misunderstanding the actual issue because running this line:
document.getElementsByTagName('html')[0].style['overflow-y'] = 'scroll';

on this page https://angular-ui.github.io/bootstrap/#/modal gets rid of the shift for me.

Anyway, that's just my two cents on the issue.

@RobJacobs
Copy link
Contributor

Seems this issue is isolated to having the content that is shifting in an element with the 'container' class. Using 'fluid-container' class or no container class and the content does not shift. Container class css ends up looking like:

.container {
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

With a width set to 750px based on a media query where container fluid does not set a width.

The modal window itself is shifting when the element that the modal is appended to (body) has it's scroll is set to hidden.

I'm going to dig into this more, here is the plunk I'm using for testing.

@RobJacobs
Copy link
Contributor

The plunk has been updated with a proposed fix. This works on Chrome and Firefox, but now the content shifts left for Edge and IE-11. If that's a trade off we are willing to make, let me know and I will create a PR. Changes are:

New function in $uibPosition service:

  /**
   * Provides the padding required on an element to replace the scrollbar.
   *
   * @returns {object} An object with the following properties:
   *     <li>**widthOverflow**: whether the the width is overflowing</li>
   *     <li>**right**: the amount of right padding on the element needed to replace the scrollbar</li>
   *     <li>**rightOriginal**: the amount of right padding currently on the element</li>
   *     <li>**heightOverflow**: whether the the height is overflowing</li>
   *     <li>**bottom**: the amount of bottom padding on the element needed to replace the scrollbar</li>
   *     <li>**bottomOriginal**: the amount of bottom padding currently on the element</li>
   *   </ul>
   */
  scrollbarPadding: function(elem) {
    elem = this.getRawNode(elem);

    var elemStyle = $window.getComputedStyle(elem);
    var paddingRight = this.parseStyle(elemStyle.paddingRight);
    var paddingBottom = this.parseStyle(elemStyle.paddingBottom);
    var scrollParent = this.scrollParent(elem);
    return {
      widthOverflow: scrollParent.scrollWidth > scrollParent.clientWidth,
      right: paddingRight + this.scrollbarWidth(),
      originalRight: paddingRight,
      heightOverflow: scrollParent.scrollHeight > scrollParent.clientHeight,
      bottom: paddingBottom + this.scrollbarWidth(),
      originalBottom: paddingBottom
     };
  },

Then in the modal - $modalStack.open function:

    if (!modal.scope.$$uibDestructionScheduled) {
      scrollbarPadding = $uibPosition.scrollbarPadding(appendToElement);
      if (scrollbarPadding.heightOverflow) {
        appendToElement.css({paddingRight: scrollbarPadding.right + 'px'});
      }
      $animate.addClass(appendToElement, modalBodyClass);
    }
    $animate.enter($compile(angularDomEl)(modal.scope), appendToElement);

and in the modal - removeModalWindow function:

    removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function() {
      var modalBodyClass = modalWindow.openedClass || OPENED_MODAL_CLASS;
      openedClasses.remove(modalBodyClass, modalInstance);
      appendToElement.toggleClass(modalBodyClass, openedClasses.hasKey(modalBodyClass));
      if (scrollbarPadding && scrollbarPadding.heightOverflow) {
        if (scrollbarPadding.originalRight) {
          appendToElement.css({paddingRight: scrollbarPadding.originalRight + 'px'});
        } else {
          appendToElement.css({paddingRight: ''});
        }
        scrollbarPadding = null;
      }
      toggleTopWindowClass(true);
    }, modalWindow.closedDeferred);

@wesleycho
Copy link
Contributor

@RobJacobs do you have any idea whether you could come up with a solution for Edge/IE? Is there something wrong with the width calculation in that situation?

@RobJacobs
Copy link
Contributor

@wesleycho To summarize:

The difference has to do with browsers whose scrollbars overlay (Edge/IE) vs render inline (Chrome/Firefox). The content shift in Chrome is because the browser is trying to center align elements with a fixed width and left/right margins of auto. I'm going to do some more digging to see what (or if) is the best way to detect this scenario.

_EDIT_

Related to PR #879

@deeg
Copy link
Contributor

deeg commented Mar 16, 2016

@RobJacobs, @wesleycho, where did we leave off with this?

Should we attempt at looking to fix IE/Edge with Rob's solution? Should we be looking for a different solution all together?

@RobJacobs
Copy link
Contributor

@deeg Sorry, I got side tracked. The issue all stems from the .modal-open class that gets added to the body element which just sets overflow: hidden to kill scroll on the body. If we could live with the scrollbar staying visible and use a scroll event on the modal backdrop element to stopPropagation, it would be a cleaner solution.

@deeg
Copy link
Contributor

deeg commented Mar 16, 2016

I guess I'm fine with that approach, but it would be different from how regular bootstrap handles it right?

@wesleycho, thoughts?

@RobJacobs
Copy link
Contributor

After some more digging, it seems how TWBS measures the scrollbar width is flawed. In IE/Edge, the html or body element scrollbars overlay, where in Chrome they render inline. To get the true scrollbar width for the html or body element, it needs to be calculated as:

$window.innerWidth - bodyElem[0].offsetWidth

rather than:

scrollElem[0].offsetWidth - scrollElem[0].clientWidth

Which correctly reports 0 for IE and Edge, 17 for chrome. I added an isBody parameter to the scrollbarWidth function to determine which calc should be done. I'm wondering if creating a new bodyScrollbarWidth function would be clearer instead? The plunk has been updated with the fix.

@wesleycho
Copy link
Contributor

Awesome find - I'm fine with that.

This should also be reported to the Bootstrap guys so they can gain the fruits of these findings.

@weijyewang
Copy link

Hi, I observe this issue occurs again on Chrome 57.0.2987.133 (64-bit), but it is working fine in IE11. I'm using ui-bootstrap-tpls-2.0.1, which should already contains the fixes above.

Do you think that the latest chrome update breaks it again?

@amitdubeyup
Copy link

Use this code, May this can resolve your issue
body.modal-open{
width:100% !important;
padding-right:0 !important;
overflow-y:scroll !important;
position:fixed !important;
}

@TilmannBach
Copy link

TilmannBach commented Sep 4, 2017

@amitdubey8888 you code works and the background doesnt move now but it generates two scrollbars

see the screenshot (tested in chrome 57)

image

@amitdubeyup
Copy link

You can hide scrollbar also, by using this code

.modal{
overflow-y: hidden !important;
}

@OlexandrPopov
Copy link

OlexandrPopov commented Oct 2, 2017

The issue is back in angular-ui 2.5.0. It can be reproduced on the demo page http://angular-ui.github.io/bootstrap/#!#modal
You can compare it with angular-ui 1.3.1 where it's fixed http://angular-ui.github.io/bootstrap/versioned-docs/1.3.1/#/modal

@kuzinmv
Copy link

kuzinmv commented Dec 28, 2017

Moving the container a few pixels down when you open the modal happen if you have a < nav > section of fixed height, but tags contained inside this section a slightly higher. Make the height of internal tags to be less or equal than the height of the < nav > section and container the shift effect will be lost.

2017-12-28 10 06 34

2017-12-28 10 07 24

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.