fix(portal-admin): html/body overflow-y hidden as a shell shield #176

Merged
julien merged 1 commits from fix/admin-shell-overflow-shield into main 2026-05-17 01:56:27 +02:00
Owner

Summary

Tiny follow-up to #175 — the bar / donut / stacked-bar charts on the audit-log Charts tab still surfaced a phantom body scrollbar plus an empty band below the footer in some viewport widths. The lib-side overflow constraints from #175 hold for the cases tested, but the symptom can re-appear from any future layout escape (a wider downstream component, a third-party iframe, an unforeseen flex bug).

This PR adds a html, body { overflow-y: hidden } shield at the global stylesheet so any vertical overflow at the document level — wherever it comes from — stops at the shell boundary instead of producing a phantom scrollbar. Element-level scrolling on <main> (the only surface that should scroll) is unaffected.

What lands

apps/portal-admin/src/styles.css:

html,
body {
  overflow-y: hidden;
}

That's the whole change. The admin shell already commits to the "fills the viewport, never scrolls the body" layout — <app-root> is locked at height: 100vh and <main> owns its own overflow-y: auto. Anything that escapes that contract is, by design, a bug to fix at the source. The shield is a safety net, not a load-bearing layout rule.

Notes for the reviewer

  • Why only portal-admin? portal-shell's app.scss carries the exact same height: 100vh + <main> overflow-y: auto shape, so the same shield would make sense there too. Holding it back to a separate PR because portal-shell hasn't actually demonstrated the symptom and the audit-log chantier is the immediate motivation — a one-line shield to the public-facing app deserves its own minute of consideration. Trivial to extend if/when we want symmetry.
  • Why not just delete height: 100vh and let the document scroll naturally? The admin shell deliberately keeps the header, sidebar, and footer pinned while only the content area scrolls — that's a deliberate UX choice for a dense admin surface (long audit-log tables, future CMS editors), not an accident. Keeping the 100vh contract and adding the shield preserves the intent.
  • Manual reproduction of the original symptom (now fixed): pre-shield, switching to the Charts tab on a 1280×720 viewport produced a body scrollbar with ~12 px of empty space below the footer, even though every visible element was inside <main>. Post-shield, the body scrollbar is gone; <main>'s internal scrollbar still works for the table page below the fold.

Test plan

  • pnpm nx build portal-admin — clean.
  • pnpm nx test portal-admin — 62 specs pass (no behavioural change).
  • pnpm nx lint portal-admin — same three pre-existing warnings, no new ones.
  • Manual smokepnpm nx serve portal-admin, sign in with Portal.Admin:
    • Navigate to /admin/audit, switch to Charts — no body scrollbar, no gap under the footer, charts still render at the column width.
    • Resize the viewport across the (max-width: 800px) breakpoint — body still doesn't scroll; <main> still does where it should.
    • Open the user-list page (long table) — <main> scrolls internally as expected; the shield does not prevent legitimate content scrolling.
    • Toggle dark mode — no visual regression.

What's next

  • Mirror the same shield into apps/portal-shell/src/styles.css if/when a layout escape shows up there. Tracked in docs/decisions/0020-portal-admin-app.md follow-ups.
## Summary Tiny follow-up to #175 — the bar / donut / stacked-bar charts on the audit-log Charts tab still surfaced a *phantom* body scrollbar plus an empty band below the footer in some viewport widths. The lib-side overflow constraints from #175 hold for the cases tested, but the symptom can re-appear from any future layout escape (a wider downstream component, a third-party iframe, an unforeseen flex bug). This PR adds a `html, body { overflow-y: hidden }` shield at the global stylesheet so any vertical overflow at the document level — wherever it comes from — stops at the shell boundary instead of producing a phantom scrollbar. Element-level scrolling on `<main>` (the only surface that *should* scroll) is unaffected. ## What lands `apps/portal-admin/src/styles.css`: ```css html, body { overflow-y: hidden; } ``` That's the whole change. The admin shell already commits to the "fills the viewport, never scrolls the body" layout — `<app-root>` is locked at `height: 100vh` and `<main>` owns its own `overflow-y: auto`. Anything that escapes that contract is, by design, a bug to fix at the source. The shield is a safety net, not a load-bearing layout rule. ## Notes for the reviewer - **Why only portal-admin?** `portal-shell`'s app.scss carries the exact same `height: 100vh` + `<main> overflow-y: auto` shape, so the same shield would make sense there too. Holding it back to a separate PR because portal-shell hasn't actually demonstrated the symptom and the audit-log chantier is the immediate motivation — a one-line shield to the public-facing app deserves its own minute of consideration. Trivial to extend if/when we want symmetry. - **Why not just delete `height: 100vh` and let the document scroll naturally?** The admin shell deliberately keeps the header, sidebar, and footer pinned while only the content area scrolls — that's a deliberate UX choice for a dense admin surface (long audit-log tables, future CMS editors), not an accident. Keeping the 100vh contract and adding the shield preserves the intent. - **Manual reproduction of the original symptom** (now fixed): pre-shield, switching to the Charts tab on a 1280×720 viewport produced a body scrollbar with ~12 px of empty space below the footer, even though every visible element was inside `<main>`. Post-shield, the body scrollbar is gone; `<main>`'s internal scrollbar still works for the table page below the fold. ## Test plan - [x] `pnpm nx build portal-admin` — clean. - [x] `pnpm nx test portal-admin` — 62 specs pass (no behavioural change). - [x] `pnpm nx lint portal-admin` — same three pre-existing warnings, no new ones. - [ ] **Manual smoke** — `pnpm nx serve portal-admin`, sign in with `Portal.Admin`: - Navigate to `/admin/audit`, switch to Charts — no body scrollbar, no gap under the footer, charts still render at the column width. - Resize the viewport across the `(max-width: 800px)` breakpoint — body still doesn't scroll; `<main>` still does where it should. - Open the user-list page (long table) — `<main>` scrolls internally as expected; the shield does *not* prevent legitimate content scrolling. - Toggle dark mode — no visual regression. ## What's next - Mirror the same shield into `apps/portal-shell/src/styles.css` if/when a layout escape shows up there. Tracked in `docs/decisions/0020-portal-admin-app.md` follow-ups.
julien added 1 commit 2026-05-17 01:56:08 +02:00
fix(portal-admin): html/body overflow-y hidden as a shell shield
CI / commits (pull_request) Successful in 3m54s
CI / scan (pull_request) Successful in 3m57s
CI / check (pull_request) Successful in 4m27s
CI / a11y (pull_request) Successful in 2m21s
CI / perf (pull_request) Successful in 5m57s
e531ca5e24
The admin shell is a "fills 100vh, never scrolls the body" layout —
<app-root> is height: 100vh and <main> owns its own overflow-y. If
anything ever pushes content past the viewport (a chart sizing
escape, a future iframe, a flex bug), we'd rather clip at the root
than show a phantom body scrollbar plus the empty space under the
footer that comes with it.
julien merged commit 67e50be1dc into main 2026-05-17 01:56:27 +02:00
julien deleted branch fix/admin-shell-overflow-shield 2026-05-17 01:56:30 +02:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: julien/apf_portal#176