From 511182b41b1c754f382490d0628bd2b9e7942b4e Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Tue, 17 Jan 2023 11:56:16 -0500 Subject: [PATCH] add padding to offset scrollbar; fixes #1132 --- docs/resources/changelog.md | 1 + src/internal/scroll.ts | 16 +++++++++++++++- src/themes/_utility.css | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md index 860d1c85a..2f17a43e1 100644 --- a/docs/resources/changelog.md +++ b/docs/resources/changelog.md @@ -26,6 +26,7 @@ New versions of Shoelace are released as-needed and generally occur when a criti - Fixed a bug in `` that caused the animation to stop working correctly in Safari [#1121](https://github.com/shoelace-style/shoelace/issues/1121) - Fixed a bug that prevented the entire `` to be hidden when inactive - Fixed a bug that caused the value of `` to be `undefined` depending on where the radio was activated [#1134](https://github.com/shoelace-style/shoelace/issues/1134) +- Fixed a bug that caused body content to shift when scroll locking was enabled [#1132](https://github.com/shoelace-style/shoelace/issues/1132) - Refactored the `ShoelaceFormControl` interface to remove the `invalid` property, allowing a more intuitive API for controlling validation internally - Renamed the internal `FormSubmitController` to `FormControlController` to better reflect what it's used for - Updated Lit to 2.6.1 diff --git a/src/internal/scroll.ts b/src/internal/scroll.ts index 89e994bae..02dee14e3 100644 --- a/src/internal/scroll.ts +++ b/src/internal/scroll.ts @@ -2,13 +2,26 @@ import { getOffset } from './offset'; const locks = new Set(); +/** Returns the width of the document's scrollbar */ +function getScrollbarWidth() { + const documentWidth = document.documentElement.clientWidth; + return Math.abs(window.innerWidth - documentWidth); +} + /** * Prevents body scrolling. Keeps track of which elements requested a lock so multiple levels of locking are possible * without premature unlocking. */ export function lockBodyScrolling(lockingEl: HTMLElement) { locks.add(lockingEl); - document.body.classList.add('sl-scroll-lock'); + + // When the first lock is created, set the scroll lock size to match the scrollbar's width to prevent content from + // shifting. We only do this on the first lock because the scrollbar width will measure zero after overflow is hidden. + if (!document.body.classList.contains('sl-scroll-lock')) { + const scrollbarWidth = getScrollbarWidth(); // must be measured before the `sl-scroll-lock` class is applied + document.body.classList.add('sl-scroll-lock'); + document.body.style.setProperty('--sl-scroll-lock-size', `${scrollbarWidth}px`); + } } /** @@ -19,6 +32,7 @@ export function unlockBodyScrolling(lockingEl: HTMLElement) { if (locks.size === 0) { document.body.classList.remove('sl-scroll-lock'); + document.body.style.removeProperty('--sl-scrollbar-width'); } } diff --git a/src/themes/_utility.css b/src/themes/_utility.css index c74953a07..eab968349 100644 --- a/src/themes/_utility.css +++ b/src/themes/_utility.css @@ -5,6 +5,7 @@ */ .sl-scroll-lock { + padding-right: var(--sl-scroll-lock-size) !important; overflow: hidden !important; }