Fix modal-open layout shift caused by position:fixed scroll lock

Replace the body position:fixed hack with overflow:hidden on html element,
which works cleanly with scrollbar-gutter:stable to prevent layout shift.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 22:37:10 +03:00
parent 997ff2fd70
commit 43fbc1eff5
3 changed files with 6 additions and 13 deletions

View File

@@ -91,10 +91,8 @@ body {
line-height: 1.6;
}
body.modal-open {
position: fixed;
width: 100%;
overflow-y: scroll; /* keep scrollbar gutter to prevent layout shift */
html.modal-open {
overflow: hidden; /* scrollbar-gutter: stable keeps the gutter reserved */
}
/* ── Ambient animated background ── */

View File

@@ -296,7 +296,7 @@ export async function openCommandPalette() {
const overlay = document.getElementById('command-palette')!;
const input = document.getElementById('cp-input') as HTMLInputElement;
overlay.style.display = '';
document.body.classList.add('modal-open');
document.documentElement.classList.add('modal-open');
input.value = '';
input.placeholder = t('search.placeholder');
_loading = true;
@@ -318,7 +318,7 @@ export function closeCommandPalette() {
_isOpen = false;
const overlay = document.getElementById('command-palette')!;
overlay.style.display = 'none';
document.body.classList.remove('modal-open');
document.documentElement.classList.remove('modal-open');
_items = [];
_filtered = [];
}

View File

@@ -67,13 +67,10 @@ export function setupBackdropClose(modal: any, closeFn: () => void) {
}
let _lockCount = 0;
let _savedScrollY = 0;
export function lockBody() {
if (_lockCount === 0) {
_savedScrollY = window.scrollY;
document.body.style.top = `-${_savedScrollY}px`;
document.body.classList.add('modal-open');
document.documentElement.classList.add('modal-open');
}
_lockCount++;
}
@@ -82,9 +79,7 @@ export function unlockBody() {
if (_lockCount <= 0) return;
_lockCount--;
if (_lockCount === 0) {
document.body.classList.remove('modal-open');
document.body.style.top = '';
window.scrollTo({ top: _savedScrollY, behavior: 'instant' });
document.documentElement.classList.remove('modal-open');
}
}