mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 14:16:12 +00:00
Give the scroll container its own containing block
`<main id="main-content">` scrolls the authenticated shell, but it was `position: static`, so an absolutely-positioned descendant with no nearer positioned ancestor resolved against the initial containing block. That block sits outside the scroll container: `overflow-y-auto` never clipped those boxes, and their static position extended the DOCUMENT's scrollable overflow instead. The result is a second vertical scroll surface beside `<main>`, which UI-STANDARDS §9 forbids. The escapees are library markup, so no per-component wrapper would have caught them. A Radix `<Switch>` outside a `<form>` renders a hidden `position:absolute` bubble input on its first pass and drops it only once the button ref resolves, and the root `loading.tsx` chart skeleton carries an `sr-only` announcement that lives until the real content streams in. Both are gone within a few hundred milliseconds of hydration, so the page carried a full-height document scrollbar for the whole pre-hydration window and looked clean immediately after. On /settings/modules at a 390x844 viewport the document measured 1952 px against an 844 px viewport while the switches were still bubble-inputs. Anchoring the scroll container closes the escape route for every such box at once. The over-scroll guard grows the matching structural assertion: `<main>` must not compute to `position: static`. The height read it already had can only see an escapee that happens to be mounted at measure time, which is why it went red on a loaded CI runner and green on the same tree twenty minutes earlier; the computed style is timing-free and fails on every route and both viewports the moment the anchor is removed.
This commit is contained in:
1 parent
6d4eefe26b
commit
1b7dff411a
2 files changed
+53
-10
No files matched your search
@@ -319,7 +319,25 @@ export function AuthShell({
|
||||
// wrapper then recentres and the whole column, including the
|
||||
// admin/settings sidebar, shifts a few px sideways on every
|
||||
// toggle. Reserving the gutter holds the layout still.
|
||||
className="flex-1 [scrollbar-gutter:stable] overflow-y-auto pb-[calc(4rem+env(safe-area-inset-bottom,0px))] md:pb-0"
|
||||
//
|
||||
// `relative` makes this element the containing block for every
|
||||
// absolutely-positioned descendant that has no nearer positioned
|
||||
// ancestor. Without it those boxes resolve against the INITIAL
|
||||
// containing block, which lives outside the scroll container, so
|
||||
// `overflow-y-auto` never clips them: their static position sits
|
||||
// wherever the flow put them and extends the DOCUMENT's
|
||||
// scrollable overflow instead, painting a second vertical scroll
|
||||
// surface beside `<main>` (UI-STANDARDS §9 one-scroll-floor).
|
||||
// The class is not hypothetical and not confined to app code. A
|
||||
// Radix `<Switch>` outside a `<form>` renders a hidden
|
||||
// `position:absolute` bubble input on the first pass and drops it
|
||||
// only once the button ref resolves, so every route carrying a
|
||||
// switch below the fold (/settings/modules is the long one) grew
|
||||
// a full-height document scrollbar for the entire pre-hydration
|
||||
// window. Anchoring the scroll container closes the escape route
|
||||
// for all of them at once instead of asking each new
|
||||
// absolutely-positioned child to remember its own wrapper.
|
||||
className="relative flex-1 [scrollbar-gutter:stable] overflow-y-auto pb-[calc(4rem+env(safe-area-inset-bottom,0px))] md:pb-0"
|
||||
>
|
||||
{/*
|
||||
v1.4.33 IW9 — container normalised on `max-w-screen-xl`
|
||||
|
||||
Reference in new issue
Block a user