Locking Body Scroll Must Not Shift the Page
SHOULD: Opening a dialog must not shift the page behind it. `document.body.style.overflow = "hidden"` removes the scrollbar track, so the viewport grows ~15px and everything behind the scrim jumps sideways (and back on close). Reserve the track with `scrollbar-gutter: stable` (or pad by `window.innerWidth - document.documentElement.clientWidth` on legacy targets), and put `overscroll-behavior: contain` on the dialog's own scroll area so a flick inside it does not chain out.
The usual overflow:hidden scroll lock removes the scrollbar, which reflows the whole page ~15px wider behind the scrim
html { scrollbar-gutter: stable; }
.dialog-body { overscroll-behavior: contain; }Bad
Good
Why it matters
Locking background scroll while a dialog is open is correct. The one-line way everyone does it — `document.body.style.overflow = "hidden"` — is what causes the lurch. On any platform with classic overlay-less scrollbars, hiding overflow removes the scrollbar track, the viewport gets roughly 15px wider, and every centered or full-width element behind the scrim jumps sideways at the exact moment the user's attention moves to the dialog.
Then it jumps back on close. It reads as a bug even to people who cannot name it. Two fixes, use both: `scrollbar-gutter: stable` on the scroll container reserves the track permanently so removing the scrollbar changes nothing (or, on legacy targets, pad by `window.innerWidth - documentElement.clientWidth`), and `overscroll-behavior: contain` on the dialog's own scroll area stops a flick inside it from chaining out to the page.
That second half is interactions-overscroll-behavior and it is a genuinely different failure — chaining is about where a scroll *goes*, this is about the layout *shifting* when scrolling is taken away.