Phone layout: opaque status bar and one safe-area rule for every edge
Each fix to the home-screen app's layout on iOS broke something else, and they
all traced back to black-translucent: it runs the page under the clock, so any
top-anchored control without its own inset sat behind it (the play view's back
button), and since iOS 26 it sizes the app one status bar short with a strip at
the bottom that CSS cannot paint (WebKit 301108). The status bar is opaque now
("black"), the page starts below it, and lib/fullHeight.ts - the JS workaround
for the short viewport - is gone with the CSS that depended on it.
viewport-fit=cover stays, so everything against a screen edge now adds that
edge's inset from shared --safe-* variables: the corner back button, the
remote-assign button, the assign toast, the tool buttons and the tab rail did
not before. The rules are written down under "Layout on phones" in the README.
On a phone held sideways the mini player and the tabs share one row instead of
taking half the screen.
Home-screen installs read the status-bar tag once: remove and re-add the app.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -159,6 +159,37 @@ Nunito is self-hosted in `public/fonts/` (one variable file per subset, ~74 kB)
|
||||
than pulled from Google. The mouse may have no internet, and a cached shell rendering in
|
||||
a fallback face looks broken.
|
||||
|
||||
## Layout on phones
|
||||
|
||||
Phones (`usePhoneLayout`: narrow, or short landscape on touch) get the touch layout in
|
||||
`components/mobile/`; tablets and the kiosk keep the keyboard one. The home-screen app
|
||||
on iOS has caught every shortcut taken here, so these are the rules - follow them rather
|
||||
than patching one element at a time:
|
||||
|
||||
- **The status bar is opaque** (`apple-mobile-web-app-status-bar-style: black`). The page
|
||||
starts below it, so nothing can end up under the clock. `black-translucent` looks
|
||||
nicer, but it ran the page behind the status bar, and since iOS 26 it also sizes the
|
||||
app one status bar short, leaving a strip at the bottom that CSS cannot paint
|
||||
([WebKit 301108](https://bugs.webkit.org/show_bug.cgi?id=301108)). The workarounds for
|
||||
that (`100lvh`, measuring `screen` in JS) each broke something else. Installed apps
|
||||
read this tag once: after changing it, remove the app and add it again.
|
||||
- **`viewport-fit=cover` stays**, so the sea fills the rounded corners and the home
|
||||
indicator area, which means:
|
||||
- **Anything placed against a screen edge adds that edge's inset**: `--safe-top`,
|
||||
`--safe-right`, `--safe-bottom` and `--safe-left` in `app.css`, always the variables
|
||||
and never a bare `env()`. That covers `top`/`bottom`/`left`/`right` offsets of
|
||||
positioned elements, and the padding of bars and scroll containers that reach the
|
||||
edge. Scrolling content clears what floats over it (`--m-dock-clearance`). The top
|
||||
inset is 0 with the opaque status bar, but stays in the formulas for Safari tabs and
|
||||
landscape.
|
||||
- **The stage is pinned, not sized**: `position: fixed; inset: 0` on phones, with the sea
|
||||
colour on `html`/`body` so any gap would show sea, not white. No viewport-height unit
|
||||
is trusted in the home-screen app.
|
||||
- **The keyboard is measured, not assumed**: iOS slides it over the page without resizing
|
||||
anything, so the dock is raised by `visualViewport` (`useKeyboardInset`) and drops its
|
||||
home-indicator padding while the keyboard is up
|
||||
([safe-area-inset-bottom does not update for the keyboard](https://webventures.rejh.nl/blog/2025/safe-area-inset-bottom-does-not-update/)).
|
||||
|
||||
## Not implemented
|
||||
|
||||
The mockup's second page, "Mein Zimmer" (Hue lights, a roller shutter and scenes), is
|
||||
|
||||
Reference in New Issue
Block a user