Cap the injected bar's z-index so a foreign host's own overlays win #35

Merged
geusebio merged 1 commit from fix/topbar-toast-stacking into main 2026-08-14 11:28:49 +00:00
Owner

What

bar.js's injected #gooo-topbar had no z-index of its own, so on a foreign
host (Jellyfin, git.grey.ooo) it fell back to brand-kit.css's
.gooo-topbar { z-index: 1000 } — the value meant for the bar sitting
inside a gooo-shell, not layered over a page this kit doesn't own.

Why

Observed live on git.grey.ooo: Forgejo's own failure notifications
(showErrorToast, e.g. "server error: 500") and other toasts render clipped
behind the injected bar instead of on top of it.

Confirmed against git.grey.ooo's real deployed CSS: Forgejo's toast layer
(.toastify) is position: fixed; z-index: 500. At z-index 1000 the bar
always won. Forgejo's own #navbar is position: static, so the bar never
needed a z-index that high to stay above the host's persistent chrome —
static elements always lose to a positioned one regardless of z-index. Only
the host's transient overlays (toasts, dropdowns, modals) compete on the
number, and those are exactly what must render on top.

Fix

Cap the injected bar's z-index at 10 in bar.js's own host-override
<style> block (the same injection point Jellyfin's .skinHeader/
.mainDrawer rules already use) — comfortably below Forgejo's 500, still
above any non-positioned host content.

Verification

  • Reproduced live against git.grey.ooo (Chrome, authenticated session): with
    the pre-fix z-index (1000) a fabricated failure toast — real .toastify
    class, position and z-index taken from Forgejo's own deployed stylesheet —
    rendered almost entirely hidden behind the bar's translucent background;
    with the fix (10) it rendered fully on top.
  • Added tools/conformance/stacking-check.mjs: an offline Playwright check
    that mounts the actual <style> override read out of bar.js's own
    source (not duplicated) against that same synthetic failure toast, and
    asserts it isn't clipped. Confirmed it fails against the pre-fix code and
    passes against the fix.
  • composer validate --strict --no-check-publish passes (no PHP touched).

No screenshots on this PR: the affected surface is Forgejo's own chrome on
git.grey.ooo, which this bundle doesn't render into directly (bar.js is
injected there by Infrastructure's own copy, not this repo's build), so
there's no consuming app this repo can point at the branch to capture
before/after pixels from. Verification above was against the live host and
the new offline check.

## What `bar.js`'s injected `#gooo-topbar` had no z-index of its own, so on a foreign host (Jellyfin, git.grey.ooo) it fell back to brand-kit.css's `.gooo-topbar { z-index: 1000 }` — the value meant for the bar sitting *inside* a gooo-shell, not layered over a page this kit doesn't own. ## Why Observed live on git.grey.ooo: Forgejo's own failure notifications (`showErrorToast`, e.g. "server error: 500") and other toasts render clipped behind the injected bar instead of on top of it. Confirmed against git.grey.ooo's real deployed CSS: Forgejo's toast layer (`.toastify`) is `position: fixed; z-index: 500`. At z-index 1000 the bar always won. Forgejo's own `#navbar` is `position: static`, so the bar never needed a z-index that high to stay above the host's *persistent* chrome — static elements always lose to a positioned one regardless of z-index. Only the host's *transient* overlays (toasts, dropdowns, modals) compete on the number, and those are exactly what must render on top. ## Fix Cap the injected bar's z-index at `10` in `bar.js`'s own host-override `<style>` block (the same injection point Jellyfin's `.skinHeader`/ `.mainDrawer` rules already use) — comfortably below Forgejo's 500, still above any non-positioned host content. ## Verification - Reproduced live against git.grey.ooo (Chrome, authenticated session): with the pre-fix z-index (1000) a fabricated failure toast — real `.toastify` class, position and z-index taken from Forgejo's own deployed stylesheet — rendered almost entirely hidden behind the bar's translucent background; with the fix (10) it rendered fully on top. - Added `tools/conformance/stacking-check.mjs`: an offline Playwright check that mounts the actual `<style>` override read out of `bar.js`'s own source (not duplicated) against that same synthetic failure toast, and asserts it isn't clipped. Confirmed it fails against the pre-fix code and passes against the fix. - `composer validate --strict --no-check-publish` passes (no PHP touched). No screenshots on this PR: the affected surface is Forgejo's own chrome on git.grey.ooo, which this bundle doesn't render into directly (bar.js is injected there by Infrastructure's own copy, not this repo's build), so there's no consuming app this repo can point at the branch to capture before/after pixels from. Verification above was against the live host and the new offline check.
`#gooo-topbar` had no z-index of its own when bar.js injects it over a
foreign host (Jellyfin, git.grey.ooo), so it inherited brand-kit.css's
`.gooo-topbar { z-index: 1000 }` — the value meant for the bar sitting
inside a gooo-shell, not layered over a page this kit doesn't own.

Confirmed against git.grey.ooo: Forgejo's own toast layer (`.toastify`)
is `position: fixed; z-index: 500`, so the bar always won and a failure
notification (`showErrorToast`, persistent — duration: -1) rendered
clipped behind the bar's translucent background instead of on top of it.

Cap the injected bar at z-index: 10 instead. It still wins against a
foreign host's persistent chrome for free (Forgejo's own #navbar is
`position: static`, and static elements always lose to a positioned one
regardless of z-index) but now loses to the host's own transient UI,
which is the layer that actually needs to stay on top.

Adds tools/conformance/stacking-check.mjs: an offline Playwright check
that mounts the actual override bar.js injects (read from its source,
not duplicated) against a synthetic Forgejo failure toast, and asserts
it isn't clipped. Verified it fails on the pre-fix bar.js and passes on
the fix.
geusebio force-pushed fix/topbar-toast-stacking from cc2f874c95 to 5bea8ef844 2026-08-14 11:07:49 +00:00 Compare
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Grey.ooo/symfony-brand-kit!35
No description provided.