fix(layout): reserve the scrollbar gutter so the nav no longer shifts

The authenticated shell scrolls inside its own `<main>` (the body is height-
locked with `flex h-dvh`), and that `<main>` centres its content with
`mx-auto`. A tall section paints the vertical scrollbar and narrows the
content box; a short one hides it and widens the box, so the whole column —
including the admin/settings sidebar — recentres a few px sideways on every
view switch. The admin "Insights Quality" ↔ "Integrations" toggle was the
visible case.

Reserve the gutter with `scrollbar-gutter: stable` on the `<main>` scroll
viewport, and on `html` for the body-scrolled login / onboarding / standalone
pages. The content box width is now constant whether or not the bar is
painted, so the left nav no longer shifts when a scrollbar appears. The fix is
global: every signed-in route renders inside the same `<main>`, so the same
shift on settings, insights, and dashboard navigation is fixed at once. The
height-locked authenticated body never scrolls the document, so no double
gutter results.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit c1459e5ee42b7f7acbfa933a9eb7d1f5a1c6890a)
This commit is contained in:
Marc-André Bombeck committed 2026-06-02 17:10:36 +02:00
1 parent 6d1587531f
commit 94415e468e
2 files changed
+23 -1

No files matched your search

+13
View File
@@ -252,6 +252,19 @@
* {
@apply border-border outline-ring/50;
}
/*
* Reserve the scrollbar gutter on the document root so the body-scrolled
* shells (login / register / onboarding / standalone legal pages) keep a
* fixed content width whether or not the page overflows. Without it a tall
* page paints the bar and a short one hides it, and any `mx-auto` content
* recentres a few px sideways on navigation. The authenticated app shell
* scrolls inside its own `<main>` (`flex h-dvh` locks the body height, so
* the document never scrolls there) and reserves its own gutter — no
* double gutter results.
*/
html {
scrollbar-gutter: stable;
}
body {
@apply bg-background text-foreground;
}
+10 -1
View File
@@ -172,7 +172,16 @@ export function AuthShell({ children }: { children: React.ReactNode }) {
<TopBar />
<main
id="main-content"
className="flex-1 overflow-y-auto pb-[calc(4rem+env(safe-area-inset-bottom,0px))] md:pb-0"
// `scrollbar-gutter: stable` keeps the scroll viewport's content
// box a fixed width whether or not the vertical scrollbar is
// painted. Without it a route / sub-tab whose body overflows
// (e.g. the admin "Insights Quality" section) shows the bar and
// narrows the content box, while a shorter one (e.g.
// "Integrations") hides it and widens the box — the `mx-auto`
// 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 overflow-y-auto [scrollbar-gutter:stable] pb-[calc(4rem+env(safe-area-inset-bottom,0px))] md:pb-0"
>
{/*
v1.4.33 IW9 — container normalised on `max-w-screen-xl`