Lock page scroll while cookie panel is open
The preference panel is a fixed, backdrop-less card whose only scrollable region is the category list. Wheel events over the header, footer, padding, or at the list edges chained to the host page, so the page scrolled instead of the panel. Treat the open panel as the modal it already claims to be: lock document scroll while state is "panel" (compensating for scrollbar width to avoid layout shift) and add overscroll-behavior: contain to the list. Restore scroll on close and on disconnect so the page is never left frozen. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -106,6 +106,7 @@ export const THEMED_STYLES = `
|
||||
|
||||
probo-preference-panel probo-category-list {
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ import { THEMED_STYLES } from "./styles";
|
||||
|
||||
export class ProboThemedBanner extends HTMLElement {
|
||||
private shadow: ShadowRoot;
|
||||
private scrollLocked = false;
|
||||
private prevOverflow = "";
|
||||
private prevPaddingRight = "";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -150,6 +153,11 @@ export class ProboThemedBanner extends HTMLElement {
|
||||
}
|
||||
});
|
||||
|
||||
root.addEventListener("probo-state", (e: Event) => {
|
||||
const { state } = (e as CustomEvent).detail;
|
||||
this.setScrollLock(state === "panel");
|
||||
});
|
||||
|
||||
this.shadow.querySelector("[data-action=back]")?.addEventListener("click", () => {
|
||||
root.setState(root.client.hasConsent ? "hidden" : "banner");
|
||||
});
|
||||
@@ -176,6 +184,31 @@ export class ProboThemedBanner extends HTMLElement {
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
this.setScrollLock(false);
|
||||
}
|
||||
|
||||
private setScrollLock(locked: boolean): void {
|
||||
if (locked === this.scrollLocked) return;
|
||||
|
||||
const root = document.documentElement;
|
||||
|
||||
if (locked) {
|
||||
const scrollbarWidth = window.innerWidth - root.clientWidth;
|
||||
this.prevOverflow = root.style.overflow;
|
||||
this.prevPaddingRight = root.style.paddingRight;
|
||||
root.style.overflow = "hidden";
|
||||
if (scrollbarWidth > 0) {
|
||||
root.style.paddingRight = `${scrollbarWidth}px`;
|
||||
}
|
||||
} else {
|
||||
root.style.overflow = this.prevOverflow;
|
||||
root.style.paddingRight = this.prevPaddingRight;
|
||||
}
|
||||
|
||||
this.scrollLocked = locked;
|
||||
}
|
||||
|
||||
private applyTexts(config: BannerConfig): void {
|
||||
const texts = config.texts ?? {};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user