-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(modal): adjust modal background to avoid shifting
Shifting potentially occurs when a scrollbar present on the container disappears once the modal opens. The solution is taken from Bootstrap itself. Fixes #641 Closes #2508
- Loading branch information
1 parent
8170295
commit 2871316
Showing
3 changed files
with
82 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import {Injectable, Inject} from '@angular/core'; | ||
import {DOCUMENT} from '@angular/common'; | ||
|
||
|
||
const noop = () => {}; | ||
|
||
|
||
|
||
/** Type for the callback used to revert the scrollbar compensation. */ | ||
export type CompensationReverter = () => void; | ||
|
||
|
||
|
||
/** | ||
* Utility to handle the scrollbar. | ||
* | ||
* It allows to compensate the lack of a vertical scrollbar by adding an | ||
* equivalent padding on the right of the body, and to remove this compensation. | ||
*/ | ||
@Injectable() | ||
export class ScrollBar { | ||
constructor(@Inject(DOCUMENT) private _document) {} | ||
|
||
/** | ||
* Detects if a scrollbar is present and if yes, already compensates for its | ||
* removal by adding an equivalent padding on the right of the body. | ||
* | ||
* @return a callback used to revert the compensation (noop if there was none, | ||
* otherwise a function removing the padding) | ||
*/ | ||
compensate(): CompensationReverter { return !this._isPresent() ? noop : this._adjustBody(this._getWidth()); } | ||
|
||
/** | ||
* Adds a padding of the given width on the right of the body. | ||
* | ||
* @return a callback used to revert the padding to its previous value | ||
*/ | ||
private _adjustBody(width: number): CompensationReverter { | ||
const body = this._document.body; | ||
const userSetPadding = body.style.paddingRight; | ||
const paddingAmount = parseFloat(window.getComputedStyle(body)['padding-right']); | ||
body.style['padding-right'] = `${paddingAmount + width}px`; | ||
return () => body.style['padding-right'] = userSetPadding; | ||
} | ||
|
||
/** | ||
* Tells whether a scrollbar is currently present on the body. | ||
* | ||
* @return true if scrollbar is present, false otherwise | ||
*/ | ||
private _isPresent(): boolean { | ||
const rect = this._document.body.getBoundingClientRect(); | ||
return rect.left + rect.right < window.innerWidth; | ||
} | ||
|
||
/** | ||
* Calculates and returns the width of a scrollbar. | ||
* | ||
* @return the width of a scrollbar on this page | ||
*/ | ||
private _getWidth(): number { | ||
const measurer = this._document.createElement('div'); | ||
measurer.className = 'modal-scrollbar-measure'; | ||
|
||
const body = this._document.body; | ||
body.appendChild(measurer); | ||
const width = measurer.getBoundingClientRect().width - measurer.clientWidth; | ||
body.removeChild(measurer); | ||
|
||
return width; | ||
} | ||
} |