Render between the system bars deterministically; delete my inset bridge

The app sometimes drew under the status and gesture bars and sometimes
between them. Cause: Capacitor 8 ships a SystemBars plugin that already
handles insets, from a listener on the decor view, and my MainActivity
had installed another one on the WebView. Different views, so they
stacked rather than replaced each other and the result depended on which
fired last.

SystemBars switches on the viewport meta tag. With viewport-fit=cover it
passes insets through once onPageCommitVisible has checked the tag, decor
padding drops to 0 and the WebView grows 735 -> 820, leaving the page to
place itself from injected CSS vars. Without it the plugin pads the decor
view and the WebView is laid out between the bars already.

So sync-www.sh now strips viewport-fit=cover from the generated www/
(patch 5), MainActivity is an empty BridgeActivity, native.css and
native.js no longer touch insets, and bar style moves to
capacitor.config.json. No native->web handshake remains, so there is
nothing to race and no launch-time layout jump.

Verified identical across 3 cold launches, 2 resumes and an in-place
reload: h=735 padTop=8px overflowBy=0, panel 485px, pad rows 44.8px.

Costs no space: 820-45-114 and 735-8-66 both leave 661px. The bars take
the same room either way.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-16 23:26:31 +03:00
parent 5f9d89d9fb
commit 066b9e8c34
6 changed files with 83 additions and 128 deletions

View File

@@ -2,45 +2,23 @@
reference/ is never edited; sync-www.sh injects this as the last stylesheet
in <head>, so on equal specificity these rules win. */
:root{
/* Filled in from Android WindowInsets by MainActivity via __applyInsets().
The env() defaults keep the page correct in a plain desktop browser, where
env() works and the native bridge is absent. */
--ins-t: env(safe-area-inset-top, 0px);
--ins-b: env(safe-area-inset-bottom, 0px);
--ins-l: env(safe-area-inset-left, 0px);
--ins-r: env(safe-area-inset-right, 0px);
/* No inset handling here on purpose.
/* The reference derives --sab from env(safe-area-inset-bottom), which is
always 0px inside an Android WebView. Re-point it at the real inset.
.bnav and .sheet both key off --sab, so they need no further changes. */
--sab: var(--ins-b);
}
sync-www.sh strips viewport-fit=cover from the generated www/, so Capacitor's
SystemBars plugin pads the decor view and the WebView is laid out between the
status and gesture bars already. env(safe-area-inset-*) is therefore 0, the
reference's --sab resolves to 0, and .bnav and .sheet are correct as written.
An earlier version mapped --sab onto values pushed from MainActivity. That
raced with Capacitor's own listener - see CLAUDE.md. */
@media (max-width:820px){
/* The reference sets `padding: 8px 8px calc(var(--nav) + var(--sab) + 8px)`.
Bottom already accounts for --sab; add the top and side insets so the unit
panel clears the status bar and any display cutout. */
.app{
padding-top: calc(8px + var(--ins-t));
padding-left: calc(8px + var(--ins-l));
padding-right: calc(8px + var(--ins-r));
}
/* Bottom nav is position:fixed and spans the full width, so it needs the
side insets itself. Its height/padding-bottom already follow --sab. */
.bnav{
padding-left: var(--ins-l);
padding-right: var(--ins-r);
}
/* ---------- strip ergonomics (Phase 1 UI fix) ----------
The reference spaces its two chip rows with `#strip .chips + .chips`, but
on phones the .lbl heading between them is display:none and still in the
DOM, so the adjacent-sibling selector never matches and the rows sit flush
(measured: 0px gap). native.js collapses the 7 context chips into the
single .ctxbtn below, leaving one chip row with real touch targets.
Phase 2 must carry this - see CLAUDE.md. */
(measured: 0px gap). native.js collapses both rows into the two pickers
below. Phase 2 must carry this - see CLAUDE.md. */
/* Mode and layer pickers share one row: only one layer is ever active, so
neither needs a scrolling row of its own. One 44px row instead of two gives
@@ -73,8 +51,8 @@
}
}
/* Context picker rows inside the sheet. Uses CTXHINT from the reference, which
the phone layout otherwise never shows. */
/* Mode and layer rows inside the sheet. The mode rows use CTXHINT from the
reference, which the phone layout otherwise never shows. */
.ctxopt{
display: block; width: 100%; text-align: left; color: inherit;
background: var(--card); border: 1px solid var(--line); border-radius: 10px;