fix: hold the scrollbar gutter while an overlay is open - #5240
fix: hold the scrollbar gutter while an overlay is open#5240imdreamrunner wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR Analysis Report📚 Storybook PreviewView Storybook for this PR 🧪 Sandbox PreviewView Sandbox for this PR Modified ComponentsMobileNav (@astryxdesign/core) · View in Storybook
Bundle Size Summary
Accessibility AuditStatus: No accessibility violations detected. Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
…lback Refines #5219 rather than replacing its trigger. Two changes: 1. `scrollbar-gutter: stable` instead of padding. It is a real layout change, so it holds position: fixed chrome -- toast viewports, sticky docks -- which padding cannot: fixed elements resolve against the viewport, not against the padded element. 2. Applied for the duration of the lock only, never statically. A static rule in reset.css also fixes the shift (and fixes navigation jank too), but it reserves the gutter for the life of every document, including pages too short to scroll -- which never had the shift. On a one-screen full-bleed marketing page that permanently narrows the layout and pulls full-bleed art off the right edge. Measured: hero 900 -> 885, headline re-centered 7px left. The whole decision is one boolean -- does the scrollbar take layout space -- and CSS does the rest. No widths, no arithmetic, no padding to restore, and nothing at all applied on mobile or on short pages. Verified on the real components with no static rule loaded: 49/49 across Dialog/BottomSheet/MobileNav x tall/short/RTL/page-reserves-its- own-gutter x classic scrollbars, genuine overlay scrollbars, iPhone and Pixel profiles, plus nested overlays closed out of order. The short full-bleed marketing page renders byte-identically to a build with no fix at all. Engines without scrollbar-gutter (Safari <18.2) get no compensation now. Safari defaults to overlay scrollbars, where there is no shift to fix.
6567f0c to
895f4c4
Compare
|
Closing this — it turned out to be a no-op refactor with a regression, and #5219 already shipped the fix. Why#5219 landed as two commits, and the squash kept the first one's title ( Its only real delta was deleting the padding fallback. I diffed both builds over the same 36 cases (Dialog × BottomSheet × MobileNav, tall/short/RTL/page-reserves-its-own-gutter, classic + overlay scrollbars + iPhone):
What
|
Refines #5219. Same trigger — the gutter is taken only while an overlay is open — but two things change.
1.
scrollbar-gutter: stableinstead of paddingPadding an element only holds content in the document flow.
position: fixedchrome — a toast viewport, a sticky dock — resolves against the viewport and kept jumping the full 15px. Holding the gutter is a real layout change, so everything stays put.It also can't double-compensate: #5219 measured the scrollbar's width and padded by it, which on a page that already sets
scrollbar-gutter: stableshifted content 15px the wrong way. The gutter is idempotent.2. Applied dynamically, never statically
An earlier revision of this PR put
html { scrollbar-gutter: stable }inreset.css. That fixes more — navigation jank, content-growth jank, the100vwoverflow bug — but it reserves the gutter for the whole life of every document, including pages too short to scroll, which never had the shift in the first place.On a one-screen full-bleed marketing page that is a visible regression, measured at 900×600 with classic scrollbars:
100vwbandThe full-bleed gradient stops 15px short and the page background shows through as a strip down the right edge. So the rule is out of
reset.css; the gutter is taken at lock time and given back on close.The whole decision is one boolean
No widths, no arithmetic, no padding to restore. Nothing is applied where there is no gutter to hold: overlay scrollbars (mobile, macOS by default) and pages too short to scroll.
Test plan
49/49 on the real components, with no static rule loaded so this path is the only mechanism — Dialog × BottomSheet × MobileNav, across four page shapes and four environments, plus nested overlays closed out of order:
Every cell: 0px for in-flow content, 0px for
position: fixedcontent, background scroll still locked, layout and the page's ownscrollbar-guttervalue restored on close.And the case that drove the design — the short full-bleed marketing page, with this fix installed: hero 900, nav 900, headline centered 450, band 900, computed gutter
auto. Byte-identical to a build with no fix at all.Unit coverage: the helper (hold, release, overlay scrollbars, short pages, no-layout environments, nesting, out-of-order release, double-release, restoring the page's own value), the hook, and the drawer.
Gates:
pnpm lint:strict(0 errors, 56 pre-existing warnings),pnpm test(7,384 core+lab; 3,407 cli+apps),pnpm build.Known limitation
Engines without
scrollbar-gutter(Safari <18.2) get no compensation — #5219's padding fallback is gone with the padding. Safari defaults to overlay scrollbars, where there is no shift to fix; only Safari <18.2 with "always show scroll bars" turned on is affected, and it degrades to today's behavior rather than anything worse.Not doing (for now)
The static rule fixes two janks this doesn't: navigating short page → scrolling page, and content growing past the viewport (a list loads, an accordion opens). Both shift by the same 15px. If we want those, the static rule is the answer — but it's a layout change for every consumer on upgrade and belongs in its own PR, marked
[breaking]for the minor bump, not smuggled in with a modal fix.