fix(frontend): Desktop More/wallet menus clipped under EnvironmentRibbon (stacking) #486

Closed
opened 2026-07-13 11:54:31 +00:00 by PlasticDigits · 5 comments
PlasticDigits commented 2026-07-13 11:54:31 +00:00 (Migrated from gitlab.com)

Summary

Desktop bug report: opening the header More menu shows the sticky EnvironmentRibbon (mainnet MAINNET / Terra Classic · columbus-5 · real assets strip) cutting horizontally through the top of the dropdown. The menu appears behind / severed by the ribbon.

Reporter perception that the ribbon is “full width when it shouldn’t be” is mostly a stacking illusion: the ribbon is intentionally content-column width (same min(100% - 24px, 1180px) as the header). The real defect is paint order / z-index within the sticky stacking context, not that the ribbon should shrink to a compact pill.

Same stacking applies to the connected wallet dropdown (shared .app-menu / .wallet-menu rules).

Current codebase

Sticky chrome is a two-tier stack under one isolated wrapper:

  • frontend-dapp/src/components/common/Layout.tsx
    • .app-top-sticky wraps header.app-header-shell then <EnvironmentRibbon /> (DOM order: header → ribbon).
    • Desktop More renders role="menu" with class app-menu inside .app-more-wrap in the header nav.
    • Desktop/tablet omit header NetworkBadge and rely on the ribbon as the primary network signal (#483).
  • frontend-dapp/src/components/legal/EnvironmentRibbon.tsx — build-time network strip (MAINNET / TESTNET / LOCAL + detail). Not page-specific content.
  • frontend-dapp/src/index.css (relevant stacking):
    • .app-top-sticky — position: sticky; top: 0; z-index: 40; isolation: isolate (added/kept for #482 bleed-through fix).
    • .app-menu / .wallet-menu — position: absolute; top: calc(100% + 10px); z-index: 45.
    • .app-env-ribbon — no z-index; follows header in DOM; opaque panel tint so scrolled page copy cannot bleed through (#482).
    • .app-menu-dismiss — fixed overlay at z-index: 24 (below sticky stack 40).

Why the More panel loses: isolation: isolate on .app-top-sticky creates a local stacking context. Inside it, the absolutely positioned .app-menu (z-index: 45) is still a descendant of the header, while the ribbon is a later sibling with auto stacking. Later sibling paint order wins over the menu’s extension below the header, so the ribbon occludes the open dropdown. Raising .app-menu’s z-index alone does not escape the sticky isolate context relative to the ribbon sibling.

Prior related work (closed): #138 (environment strip), #482 (sticky seam + opaque ribbon / isolate), #483 (header density / More vs theme gap). Existing E2E in frontend-dapp/e2e/navigation.spec.ts covers ribbon presence, scroll bleed, More↔theme gap, and More navigation via e2e/helpers/desktop-more-nav.ts, but not open-menu vs ribbon vertical stacking / clickability.

Why a new implementation is needed

  • Broken primary navigation affordance on desktop/tablet: Protocol / Fee Tiers / Create Pair / Mint (and overflow primaries in tablet-compact More) look clipped and may be hard to hit where the ribbon overlaps.
  • Wallet account menu likely shares the same defect when open above the ribbon band.
  • #482 correctly fixed scroll bleed and seam spacing; its isolation: isolate + opaque ribbon made this occlusion visible. Need a stacking fix that preserves #482 opacity/seam goals and #138 persistent network context.
  • Local Playwright defaults (VITE_NETWORK=local) still show a ribbon; the bug is structural, not mainnet-only, but mainnet’s reddish full-width card makes the cut more obvious (matches reporter screenshot).

Constraints / guardrails

  • Keep persistent environment context under the header (#138). Do not remove the ribbon, hide it when menus open, or bury network risk copy.
  • Preserve #482: opaque-enough ribbon + sticky stack so scrolled page text cannot bleed through; do not reintroduce translucent bleed.
  • Do not regress #483 header density (≥ ~8px More↔theme/wallet gap) or #136 tablet compact nav fold.
  • Prefer CSS stacking/layout inside the shell; avoid portaling menus unless stacking cannot be fixed in-tree without breaking dismiss/focus behavior.
  • Ribbon width matching the header content column is by design — do not “fix” by shrinking the ribbon to a left-aligned pill unless product explicitly redesigns the strip.
  • Ribbon copy remains build-time from DEFAULT_NETWORK / NETWORKS — no user-controlled HTML in the strip.
  • Preserve dark/light theme tokens and existing shell visual language.
  • Keep keyboard Escape + dismiss overlay + route-change close behavior in Layout.tsx.
  • Mobile bottom More sheet (.app-mobile-more-sheet, z-index: 55) is out of scope unless a fix accidentally regresses it.

Relevant files

Path Role
frontend-dapp/src/components/common/Layout.tsx Sticky stack + More menu + dismiss overlay
frontend-dapp/src/components/legal/EnvironmentRibbon.tsx Second-bar markup
frontend-dapp/src/index.css .app-top-sticky, .app-menu, .wallet-menu, .app-env-ribbon*, .app-menu-dismiss
frontend-dapp/src/components/wallet/WalletButton.tsx (and wallet menu markup) Same absolute menu pattern
frontend-dapp/e2e/navigation.spec.ts Shell E2E to extend
frontend-dapp/e2e/helpers/desktop-more-nav.ts Desktop More click helper
docs/frontend.md (responsive / shell section) Docs drift if stacking contract changes
  1. Establish explicit stacking inside .app-top-sticky so open header menus paint above the ribbon without weakening isolate/opacity for page scroll:
    • e.g. give header.app-header-shell (or .app-more-wrap / open-menu layer) a higher z-index than .app-env-ribbon, and keep the ribbon at a lower explicit z-index (still above main content via the sticky stack’s z-index: 40).
  2. Verify .app-menu / .wallet-menu remain clickable and fully visible (including top rounded corners and first menuitem) when open over the ribbon band.
  3. Confirm .app-menu-dismiss still receives outside clicks and that menus are not trapped under an opaque sticky layer incorrectly.
  4. Optional hardening: small Playwright assertion that the open More menu’s bounding box is not intersected by the ribbon’s client rect (or that menu top edge is above ribbon occlusion via elementFromPoint at menu center-top).
  5. Avoid redesigning ribbon width/copy as part of this bugfix.

Acceptance criteria

  • On desktop (≥ HEADER_FULL_NAV_MIN_WIDTH_PX, currently 1200px) and tablet-compact header (768–1199px), open More dropdown is fully visible above the EnvironmentRibbon — no ribbon strip cutting through menu chrome or first items.
  • All More menuitems remain clickable/focusable where they visually appear (no dead zones under the ribbon).
  • Connected wallet dropdown, when open, is likewise not clipped by the ribbon.
  • EnvironmentRibbon remains visible when menus are closed; scrolled page copy still does not bleed through the ribbon (#482).
  • Sticky header + ribbon still stick correctly; main content still scrolls under the stack.
  • Dark and light themes both pass visual check for More open + mainnet/testnet/local ribbon tones.
  • Escape, dismiss overlay click, and route change still close menus.
  • Mobile More sheet and bottom nav stacking unchanged (or explicitly verified if CSS is shared).
  • No intentional narrowing/removal of the content-column ribbon as the “fix”.

Test plan (all paths)

  1. Desktop full nav (≥1200px), dark + light: open More; confirm Protocol / Fee Tiers / Create Pair (/ Mint if faucet enabled) fully visible above ribbon; click each route.
  2. Tablet compact (768–1199px): open More (includes overflow primaries); confirm no ribbon occlusion; navigate.
  3. Wallet menu: connect (simulated or extension); open wallet dropdown over the ribbon band; confirm full visibility + actions.
  4. Networks / builds: local ribbon (default Playwright), and mainnet-styled ribbon (class swap or mainnet build) — occlusion fixed in both.
  5. Scroll bleed regression (#482): on /trade (or any long page), scroll subtitle under sticky stack; ribbon text remains readable; no page copy through ribbon.
  6. Dismiss paths: open More → click overlay; open More → Escape; open More → navigate via menuitem (auto-close).
  7. Header density (#483): More↔theme/wallet gap still ≥ ~8px at 1200/1280/1440 with disconnected and connected wallet.
  8. Mobile (≤767px): bottom More sheet + theme controls still clear bottom nav; no desktop-only CSS regression.
  9. Automated: extend frontend-dapp/e2e/navigation.spec.ts (and/or helper) with open-More vs .app-env-ribbon stacking/clickability check; keep existing ribbon bleed + density tests green.

Test plan (attack / hack / abuse vectors)

UI-only chrome, but still verify:

  • Clickjacking / overlay abuse: dismiss overlay and menus cannot leave an invisible hit-layer that intercepts wallet connect or swap CTAs after close.
  • Focus trap / keyboard: Tab/Shift+Tab and Escape with More or wallet open do not strand focus under an unclickable ribbon layer; no unintended aria-hidden on live menu.
  • Pointer interception: ribbon must not steal clicks from menuitems that visually appear on top after the fix (and must not receive clicks meant for page content when a menu is open if dismiss should win).
  • XSS / injection: ribbon remains build-time strings only — no wiring of wallet or query-string content into .app-env-ribbon-detail.
  • z-index escalation: do not raise sticky/menu layers so high that they cover security/legal modals (RiskAcknowledgementModal) or wallet connect modal portals.
  • Zoom / DPR: at 110–125% zoom, menu still clears ribbon (subpixel stacking regressions).

Verification criteria

  • Manual: screenshot/recording at ~1280–1440px showing open More fully above the mainnet (or local) ribbon with no horizontal cut.
  • Playwright: new assertion fails on current main (menu top intersected / elementFromPoint hits ribbon) and passes after fix; existing #482/#483 navigation specs remain green.
  • Code review: stacking fix documented next to .app-top-sticky / menu rules; #482 isolate/opacity intent preserved; no product change to ribbon width disguised as the bugfix.
  • Related: follows #482 / #483; closes this issue when AC + tests land.
## Summary Desktop bug report: opening the header **More** menu shows the sticky **EnvironmentRibbon** (mainnet `MAINNET` / `Terra Classic · columbus-5 · real assets` strip) cutting horizontally through the top of the dropdown. The menu appears behind / severed by the ribbon. Reporter perception that the ribbon is “full width when it shouldn’t be” is mostly a stacking illusion: the ribbon is intentionally content-column width (same `min(100% - 24px, 1180px)` as the header). The real defect is **paint order / z-index within the sticky stacking context**, not that the ribbon should shrink to a compact pill. Same stacking applies to the connected **wallet** dropdown (shared `.app-menu` / `.wallet-menu` rules). ## Current codebase Sticky chrome is a **two-tier stack** under one isolated wrapper: - `frontend-dapp/src/components/common/Layout.tsx` - `.app-top-sticky` wraps `header.app-header-shell` then `<EnvironmentRibbon />` (DOM order: header → ribbon). - Desktop **More** renders `role="menu"` with class `app-menu` inside `.app-more-wrap` in the header nav. - Desktop/tablet omit header `NetworkBadge` and rely on the ribbon as the primary network signal (#483). - `frontend-dapp/src/components/legal/EnvironmentRibbon.tsx` — build-time network strip (`MAINNET` / `TESTNET` / `LOCAL` + detail). Not page-specific content. - `frontend-dapp/src/index.css` (relevant stacking): - `.app-top-sticky` — `position: sticky; top: 0; z-index: 40; isolation: isolate` (added/kept for #482 bleed-through fix). - `.app-menu` / `.wallet-menu` — `position: absolute; top: calc(100% + 10px); z-index: 45`. - `.app-env-ribbon` — no z-index; follows header in DOM; opaque panel tint so scrolled page copy cannot bleed through (#482). - `.app-menu-dismiss` — fixed overlay at `z-index: 24` (below sticky stack `40`). **Why the More panel loses:** `isolation: isolate` on `.app-top-sticky` creates a local stacking context. Inside it, the absolutely positioned `.app-menu` (`z-index: 45`) is still a **descendant of the header**, while the ribbon is a **later sibling** with auto stacking. Later sibling paint order wins over the menu’s extension below the header, so the ribbon occludes the open dropdown. Raising `.app-menu`’s z-index alone does not escape the sticky isolate context relative to the ribbon sibling. Prior related work (closed): #138 (environment strip), #482 (sticky seam + opaque ribbon / isolate), #483 (header density / More vs theme gap). Existing E2E in `frontend-dapp/e2e/navigation.spec.ts` covers ribbon presence, scroll bleed, More↔theme gap, and More navigation via `e2e/helpers/desktop-more-nav.ts`, but **not** open-menu vs ribbon vertical stacking / clickability. ## Why a new implementation is needed - Broken primary navigation affordance on desktop/tablet: Protocol / Fee Tiers / Create Pair / Mint (and overflow primaries in tablet-compact More) look clipped and may be hard to hit where the ribbon overlaps. - Wallet account menu likely shares the same defect when open above the ribbon band. - #482 correctly fixed scroll bleed and seam spacing; its `isolation: isolate` + opaque ribbon made this occlusion visible. Need a stacking fix that **preserves** #482 opacity/seam goals and #138 persistent network context. - Local Playwright defaults (`VITE_NETWORK=local`) still show a ribbon; the bug is structural, not mainnet-only, but mainnet’s reddish full-width card makes the cut more obvious (matches reporter screenshot). ## Constraints / guardrails - Keep persistent environment context under the header (#138). Do **not** remove the ribbon, hide it when menus open, or bury network risk copy. - Preserve #482: opaque-enough ribbon + sticky stack so scrolled page text cannot bleed through; do not reintroduce translucent bleed. - Do not regress #483 header density (≥ ~8px More↔theme/wallet gap) or #136 tablet compact nav fold. - Prefer CSS stacking/layout inside the shell; avoid portaling menus unless stacking cannot be fixed in-tree without breaking dismiss/focus behavior. - Ribbon width matching the header content column is **by design** — do not “fix” by shrinking the ribbon to a left-aligned pill unless product explicitly redesigns the strip. - Ribbon copy remains build-time from `DEFAULT_NETWORK` / `NETWORKS` — no user-controlled HTML in the strip. - Preserve dark/light theme tokens and existing shell visual language. - Keep keyboard Escape + dismiss overlay + route-change close behavior in `Layout.tsx`. - Mobile bottom **More** sheet (`.app-mobile-more-sheet`, `z-index: 55`) is out of scope unless a fix accidentally regresses it. ## Relevant files | Path | Role | |------|------| | `frontend-dapp/src/components/common/Layout.tsx` | Sticky stack + More menu + dismiss overlay | | `frontend-dapp/src/components/legal/EnvironmentRibbon.tsx` | Second-bar markup | | `frontend-dapp/src/index.css` | `.app-top-sticky`, `.app-menu`, `.wallet-menu`, `.app-env-ribbon*`, `.app-menu-dismiss` | | `frontend-dapp/src/components/wallet/WalletButton.tsx` (and wallet menu markup) | Same absolute menu pattern | | `frontend-dapp/e2e/navigation.spec.ts` | Shell E2E to extend | | `frontend-dapp/e2e/helpers/desktop-more-nav.ts` | Desktop More click helper | | `docs/frontend.md` (responsive / shell section) | Docs drift if stacking contract changes | ## Recommended direction 1. Establish explicit stacking **inside** `.app-top-sticky` so open header menus paint above the ribbon without weakening isolate/opacity for page scroll: - e.g. give `header.app-header-shell` (or `.app-more-wrap` / open-menu layer) a higher `z-index` than `.app-env-ribbon`, and keep the ribbon at a lower explicit z-index (still above main content via the sticky stack’s `z-index: 40`). 2. Verify `.app-menu` / `.wallet-menu` remain clickable and fully visible (including top rounded corners and first menuitem) when open over the ribbon band. 3. Confirm `.app-menu-dismiss` still receives outside clicks and that menus are not trapped under an opaque sticky layer incorrectly. 4. Optional hardening: small Playwright assertion that the open More menu’s bounding box is not intersected by the ribbon’s client rect (or that menu top edge is above ribbon occlusion via `elementFromPoint` at menu center-top). 5. Avoid redesigning ribbon width/copy as part of this bugfix. ## Acceptance criteria - [ ] On desktop (≥ `HEADER_FULL_NAV_MIN_WIDTH_PX`, currently 1200px) and tablet-compact header (768–1199px), open **More** dropdown is fully visible above the EnvironmentRibbon — no ribbon strip cutting through menu chrome or first items. - [ ] All More menuitems remain clickable/focusable where they visually appear (no dead zones under the ribbon). - [ ] Connected **wallet** dropdown, when open, is likewise not clipped by the ribbon. - [ ] EnvironmentRibbon remains visible when menus are closed; scrolled page copy still does not bleed through the ribbon (#482). - [ ] Sticky header + ribbon still stick correctly; main content still scrolls under the stack. - [ ] Dark and light themes both pass visual check for More open + mainnet/testnet/local ribbon tones. - [ ] Escape, dismiss overlay click, and route change still close menus. - [ ] Mobile More sheet and bottom nav stacking unchanged (or explicitly verified if CSS is shared). - [ ] No intentional narrowing/removal of the content-column ribbon as the “fix”. ## Test plan (all paths) 1. **Desktop full nav (≥1200px), dark + light:** open More; confirm Protocol / Fee Tiers / Create Pair (/ Mint if faucet enabled) fully visible above ribbon; click each route. 2. **Tablet compact (768–1199px):** open More (includes overflow primaries); confirm no ribbon occlusion; navigate. 3. **Wallet menu:** connect (simulated or extension); open wallet dropdown over the ribbon band; confirm full visibility + actions. 4. **Networks / builds:** local ribbon (default Playwright), and mainnet-styled ribbon (class swap or mainnet build) — occlusion fixed in both. 5. **Scroll bleed regression (#482):** on `/trade` (or any long page), scroll subtitle under sticky stack; ribbon text remains readable; no page copy through ribbon. 6. **Dismiss paths:** open More → click overlay; open More → Escape; open More → navigate via menuitem (auto-close). 7. **Header density (#483):** More↔theme/wallet gap still ≥ ~8px at 1200/1280/1440 with disconnected and connected wallet. 8. **Mobile (≤767px):** bottom More sheet + theme controls still clear bottom nav; no desktop-only CSS regression. 9. **Automated:** extend `frontend-dapp/e2e/navigation.spec.ts` (and/or helper) with open-More vs `.app-env-ribbon` stacking/clickability check; keep existing ribbon bleed + density tests green. ## Test plan (attack / hack / abuse vectors) UI-only chrome, but still verify: - [ ] **Clickjacking / overlay abuse:** dismiss overlay and menus cannot leave an invisible hit-layer that intercepts wallet connect or swap CTAs after close. - [ ] **Focus trap / keyboard:** Tab/Shift+Tab and Escape with More or wallet open do not strand focus under an unclickable ribbon layer; no unintended `aria-hidden` on live menu. - [ ] **Pointer interception:** ribbon must not steal clicks from menuitems that visually appear on top after the fix (and must not receive clicks meant for page content when a menu is open if dismiss should win). - [ ] **XSS / injection:** ribbon remains build-time strings only — no wiring of wallet or query-string content into `.app-env-ribbon-detail`. - [ ] **z-index escalation:** do not raise sticky/menu layers so high that they cover security/legal modals (`RiskAcknowledgementModal`) or wallet connect modal portals. - [ ] **Zoom / DPR:** at 110–125% zoom, menu still clears ribbon (subpixel stacking regressions). ## Verification criteria - Manual: screenshot/recording at ~1280–1440px showing open More fully above the mainnet (or local) ribbon with no horizontal cut. - Playwright: new assertion fails on current `main` (menu top intersected / `elementFromPoint` hits ribbon) and passes after fix; existing #482/#483 navigation specs remain green. - Code review: stacking fix documented next to `.app-top-sticky` / menu rules; #482 isolate/opacity intent preserved; no product change to ribbon width disguised as the bugfix. - Related: follows #482 / #483; closes this issue when AC + tests land.
PlasticDigits commented 2026-07-13 11:54:32 +00:00 (Migrated from gitlab.com)

marked as related to #482

marked as related to #482
PlasticDigits commented 2026-07-13 11:54:32 +00:00 (Migrated from gitlab.com)

marked as related to #483

marked as related to #483
PlasticDigits commented 2026-07-13 12:07:47 +00:00 (Migrated from gitlab.com)

mentioned in commit fdda3f9692

mentioned in commit fdda3f96925c2eeff0286497f0eee5e370ba3c2f
PlasticDigits commented 2026-07-13 12:07:56 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1022

mentioned in merge request !1022
PlasticDigits commented 2026-07-13 12:29:42 +00:00 (Migrated from gitlab.com)

mentioned in commit 48051b7a56

mentioned in commit 48051b7a565e0083a9daccf640ea9f0d3b133221
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-07-13 12:29:43 +00:00
Sign in to join this conversation.
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
code/cl8y-dex-terraclassic#486
No description provided.