Files
Arkie-Library-Frontend/.unipi/docs/fix/2026-06-03-mobile-menu-drawer-stacking-fix.md
TerryM 39f9cba8c7 feat(layout): full-screen mobile menu drawer matching Figma 4164-5733
Rebuild the mobile hamburger menu as a full-screen drawer that matches
the Figma design 1:1 — five nav items (全部资料 / 资料分类 / 官方推荐 /
最新更新 / 热门资料), transparent item backgrounds over the ark-bg
drawer, hairline dividers at #2B2B37, gold text on the active route,
and the existing WalletButton compact pill as the bottom CTA. Drop the
chevron-right indicators per the rendered Figma frame and remove the
old 收藏 row since it's not in the design.

Also move the drawer JSX out of <header sticky top-0 z-40> and render
it as a sibling at the layout root. The sticky+z-index header was
creating a stacking context that trapped the drawer's z-50 fixed below
the bottom nav at z-40 global, so the drawer never reached the
foreground.

Add the same iOS-safe body scroll lock used for the search overlay so
the underlying page doesn't drift while the drawer is open.
2026-06-03 21:59:31 +08:00

2.3 KiB

title, type, date
title type date
Mobile menu drawer invisible — Quick Fix quick-fix 2026-06-03

Mobile menu drawer invisible — Quick Fix

Bug

After redesigning the mobile menu to the full-screen Figma drawer (4164-5336ARK V2 - 導航菜單), tapping the hamburger toggled the icon to X but the drawer overlay never appeared on screen. Page content stayed fully visible and the bottom nav stayed on top.

Root Cause

The drawer was rendered as a child of <header className="sticky top-0 z-40 …">. A position: sticky element with a z-index creates its own stacking context, which traps the drawer's position: fixed; z-50 inside that context. Globally, the drawer ends up bound to the header's z-40 layer, while the unrelated bottom navigation (<nav className="fixed inset-x-0 bottom-0 z-40 …">) lives in the root stacking context at z-40. With equal global z, source order wins — the bottom nav paints later and the drawer never reaches the foreground.

Fix

Move the drawer JSX out of <header> and render it as a sibling at the layout root, so its fixed/z-50 positioning lives in the root stacking context and stacks above both the header and the bottom nav.

Files Modified

  • src/layouts/PublicLayout.tsx — relocated the {open ? (…) : null} mobile drawer block from inside <header> to immediately after </header>. Logic unchanged; the menuRef, click-outside handler, body scroll lock, and inner nav/CTA structure all keep working because they reference the element by ref/state, not by DOM position.

Verification

  • npx tsc --noEmit — clean.
  • npm run format then npm run format:check — clean.
  • npm test — 49/49 passing.
  • Expected on device: tapping the hamburger now reveals the dark full-screen drawer with the 5 nav items, active item in gold, and the bottom 链接钱包 CTA (or the connected-wallet pill).

Notes

  • This is the same class of issue any future fullscreen overlay should avoid: do not nest position: fixed overlays inside a position: sticky + z-index ancestor. Either render them at the layout root or use a React Portal.
  • position: sticky without z-index does not create a stacking context, but adding any z-index to it does. The header here uses both because it needs to sit above the content while scrolled.