Bad scrollbar replacement on non-integer width windows
Created by: kremerd
Bug description:
When a modal is shown on a scrollable page, the scrollbar is hidden and the page body is padded to compensate for the lost width. Depending on display settings and the browsers zoom level, this padding is sometimes applied, even when the page body is not scrollable and there is no scrollbar to begin with.
So far as I can tell this happens, when the value right = document.body.getBoundingClientRect().right
rounds up, i.e. if right - Math.floor(right) > 0.5
. You can check it yourself on this demo site (full Stackblitz).
Note that in order for the value to be non-integer, the page must be rendered in a non-native resolution. This can be done by zooming in or out of the page, or by scaling the display in system settings like these in Windows.
Tested browsers:
I tested and reproduced this bug on Windows 10 with the following browsers:
- Firefox 70.0.1
- Chrome 78.0.3904.97
- Edge 44.18362.449.0
- Internet Explorer 11.476.18362.0
Related issues:
As #28101 (closed) this issue regards the padding introduced to compensate for scrollbars. While in that issue padding is applied when the scrollbar cannot be hidden, this issue is about padding that is applied when no scrollbar was shown to begin with.
I originally posted this at https://github.com/ng-bootstrap/ng-bootstrap/issues/3448, but now realised that the same issue occurs in the plain Bootstrap implementation as well (and for the same reason).
Suggested fix
Some rounding must be applied in the method _checkScrollbar to accomodate for non-integer values:
_checkScrollbar() {
const rect = document.body.getBoundingClientRect()
this._isBodyOverflowing = Math.round(rect.left + rect.right) < window.innerWidth
this._scrollbarWidth = this._getScrollbarWidth()
}
This works for the scenarios I tested. Still, I don't understand why rect.left
is added here, so maybe I'm missing something...