From f67f84ded37ce38f9f00262028f56c333243ad8c Mon Sep 17 00:00:00 2001 From: Martin Bauer Date: Sat, 3 Oct 2026 10:29:50 +0200 Subject: [PATCH] Phone layout: make the whole document reach the bottom in the home-screen app Sizing the stage from the screen height was not enough on iOS 26: with the layout viewport a status bar short, WebKit clips at the short viewport and draws nothing below the document, so the dock still floated over a dark strip. In standalone mode `` now takes the larger of `100vh` and the screen height too, and the stage follows it. Coming back from the background, or a relaunch restoring the page, is when iOS is most likely to hand back a short viewport and it does not always fire `resize`, so the height is also re-applied on `pageshow` and `visibilitychange`. Co-Authored-By: Claude Opus 5.5 --- web/src/lib/fullHeight.ts | 4 ++++ web/src/styles/mobile.css | 22 +++++++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/web/src/lib/fullHeight.ts b/web/src/lib/fullHeight.ts index 6e56923..ef5b85e 100644 --- a/web/src/lib/fullHeight.ts +++ b/web/src/lib/fullHeight.ts @@ -34,4 +34,8 @@ export function installFullHeight(): void { apply(); window.addEventListener("resize", apply); window.addEventListener("orientationchange", apply); + // Coming back from the background (or a relaunch restoring the page) is when iOS is + // most likely to hand back a short viewport, and it does not always fire `resize`. + window.addEventListener("pageshow", apply); + document.addEventListener("visibilitychange", apply); } diff --git a/web/src/styles/mobile.css b/web/src/styles/mobile.css index 6b8d5b4..ef19668 100644 --- a/web/src/styles/mobile.css +++ b/web/src/styles/mobile.css @@ -13,17 +13,25 @@ --m-dock-clearance: calc(96px + env(safe-area-inset-bottom)); } -/* iOS can leave the layout viewport shorter than the screen in a home-screen app - - `100dvh`, and even `position: fixed; inset: 0`, come back one status bar short - so - the dock floated that far above the bottom with an empty strip below it. There the - stage takes its height from the screen instead (`--full-height` and - `data-standalone`, set by lib/fullHeight.ts only in standalone mode); everywhere else it pins to the viewport. - The sea colour underneath covers whatever might still peek through. */ +/* iOS 26 can leave the layout viewport of a home-screen app one status bar short - + `100dvh`, `innerHeight` and `position: fixed; inset: 0` all come back short, and + WebKit draws nothing below the document - so the dock floated that far above the + bottom over a dark strip. Sizing the stage alone was not enough: it got clipped at + the short viewport. The document itself has to reach the bottom of the screen, so in + standalone mode (`data-standalone` and `--full-height`, set by lib/fullHeight.ts) + `` takes the larger of `100vh` and the screen's height, and the stage follows. + Everywhere else the stage just pins to the viewport. The sea colour underneath + covers whatever might still peek through. */ html, body { background: var(--stage-deep, #001b21); } +:root[data-standalone] { + height: max(100vh, var(--full-height, 0px)); + overflow: hidden; +} + .stage[data-phone] { position: fixed; inset: 0; @@ -32,7 +40,7 @@ body { :root[data-standalone] .stage[data-phone] { bottom: auto; - height: var(--full-height); + height: max(100vh, var(--full-height, 0px)); } .m-glass {