From b9daaa5f58d670ee9cc562d39bfe363b9b4bbc49 Mon Sep 17 00:00:00 2001 From: Julien Gautier Date: Sun, 17 May 2026 02:31:15 +0200 Subject: [PATCH] fix(portal-shell): same html/body overflow-y hidden shield as admin (#177) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Mirror of #176 onto `portal-shell`. Same one-line shield, same rationale: the two apps share an identical `:host { height: 100vh }` + `
overflow-y: auto` layout, so the same defensive `html, body { overflow-y: hidden }` rule belongs on both surfaces. Brings the public-facing shell to the same posture as the admin one — any future layout escape stops at the shell boundary rather than producing a phantom body scrollbar plus an empty band below the footer. ## What lands `apps/portal-shell/src/styles.css`: ```css html, body { overflow-y: hidden; } ``` Same block as #176 with a comment that explicitly cross-references the admin shield so future contributors don't accidentally diverge the two apps. ## Notes for the reviewer - **Why now, rather than waiting for portal-shell to demonstrate the symptom?** #176's reviewer note said this would land "if/when a layout escape shows up there." The user asked for parity immediately, on the reasoning that the shell contract is the *same* on both apps — the shield is defensive and one-line, so coupling the two posture changes is cheaper than tracking a "TODO once we see it in shell". - **No new tests.** Same justification as #176 — the change is at the global stylesheet level, has no behavioural surface, and the manual repro path already exists (force a chart or wide element past the viewport; pre-shield → body scrollbar + footer gap; post-shield → clipped at the shell root, `
` still scrolls). - **Element-level scrolling on `
` is unaffected.** The skip-link, sidebar, and footer all keep their pinned positions; long routes (the user list, future content pages) scroll inside `
` as designed. ## Test plan - [x] `pnpm nx build portal-shell` — clean. - [x] `pnpm nx test portal-shell` — green. - [x] `pnpm nx lint portal-shell` — clean. - [x] `pnpm nx run-many -t build test lint -p portal-shell,portal-admin` — green (admin and shell share the build cache; touching only one file invalidates only the shell target). - [ ] **Manual smoke** — `pnpm nx serve portal-shell`: - Open `/fr` and `/en`, scroll long pages — `
` scrolls, body doesn't. - Resize across the breakpoint where the sidebar collapses — body still doesn't scroll; sidebar/footer pin correctly. - Toggle dark mode — no visual regression. ## What's next Nothing pending on this shell-shield front. The two apps are now symmetric; if a third app appears (it won't in v1) the same pattern is documented in both `styles.css` headers. --------- Co-authored-by: Julien Gautier Reviewed-on: https://git.unespace.com/julien/apf_portal/pulls/177 --- apps/portal-shell/src/styles.css | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/portal-shell/src/styles.css b/apps/portal-shell/src/styles.css index 9713bed..7744749 100644 --- a/apps/portal-shell/src/styles.css +++ b/apps/portal-shell/src/styles.css @@ -20,3 +20,18 @@ /* Brand palette tokens — shared with `portal-admin` once it ships. */ @import '../../../libs/shared/tokens/src/brand-tokens.css'; + +/* + * The shell is a "fills the viewport, never scrolls the body" layout: + * is locked at height: 100vh, and
owns its own + * overflow-y. If anything inside the shell ever pushes content past + * the viewport (a wide chart, a flex sizing bug, a third-party + * iframe), we'd rather clip than show a phantom body scrollbar plus + * the empty space below the footer that comes with it. The element- + * level overflow on
still produces a real, scrollable region + * for content that overflows by design. Same shield as portal-admin. + */ +html, +body { + overflow-y: hidden; +}