Skip to content

fix(v2): pin mobile bottom nav with sticky instead of fixed - #4155

Open
nickybmon wants to merge 3 commits into
rommapp:masterfrom
nickybmon:fix/ios-bottom-nav-sticky-position
Open

fix(v2): pin mobile bottom nav with sticky instead of fixed#4155
nickybmon wants to merge 3 commits into
rommapp:masterfrom
nickybmon:fix/ios-bottom-nav-sticky-position

Conversation

@nickybmon

Copy link
Copy Markdown

Description

On iOS Safari, the v2 mobile bottom nav (BottomNav.vue) could visually detach from the bottom of the screen during and after scrolling, ending up stuck floating mid-screen instead of pinned to the bottom edge. This reproduced consistently on a real iPhone across multiple pages (Home, Settings, Gallery, Game Details) but never in a resized desktop Safari window.

Root cause: iOS Safari has a known engine-level issue where position: fixed elements can lose their correct viewport anchor during a scroll gesture and never properly reset, even after scrolling stops. On-device debugging (via Web Inspector) confirmed the element's layout box was frozen at a stale offset — and critically, this persisted even under a manually forced, synchronous relayout (toggling display off/on), which normally forces a fresh layout pass in any browser. That ruled out a page-level CSS/JS fix aimed at position: fixed itself.

The fix switches BottomNav.vue from position: fixed to position: sticky, wrapped in a full-height, non-flow-affecting anchor (position: absolute; inset: 0 with flex-direction: column; justify-content: flex-end) so the pill's natural (un-stuck) position sits at the bottom of the full page height. position: sticky is computed through the ordinary layout pipeline rather than the separate fixed-to-viewport mechanism, so it isn't subject to the same bug. The anchor doesn't contribute to its parent's layout height (same as the old fixed element didn't), so no other view's bottom-nav clearance calculations needed to change.

Note: AppNav.vue (the top nav) still uses position: fixed and was intentionally left unchanged — it isn't meant to behave like a sticky element, and there's no evidence it has the same issue.

AI assistance disclosure

This PR was developed with Claude Code: diagnosing the bug (including live on-device debugging via Safari Web Inspector) and implementing/iterating on the fix were done in collaboration with Claude, with the author driving device testing and reviewing/directing each step.

Testing

  • Reproduced the original bug on a real iPhone (Safari) against a local dev build.
  • Verified the fix resolves it on the same device across Home, Settings, a game detail page, and gallery/platform browsing.
  • npm run typecheck, ESLint, Prettier, npm run test (636/636 passing), and npm run build all pass.

Checklist

  • I've tested the changes locally
  • I've updated relevant comments
  • I've assigned reviewers for this PR
  • I've added unit tests that cover the changes (this is a CSS/browser-layout behavioral fix not practically covered by the Vitest/happy-dom unit test environment)

Screenshots (if applicable)

N/A

iOS Safari has a known engine bug where position: fixed elements can
lose their correct viewport anchor during and after a scroll gesture,
leaving BottomNav visually detached from the bottom edge. Forcing a
relayout doesn't clear it, even synchronously and on-demand, which
points to a stale internal reference the page can't invalidate.

Switch BottomNav to position: sticky inside a full-height, non-flow
anchor (flex-end aligned), so its position is computed through the
ordinary layout pipeline instead of the buggy fixed-to-viewport path.
The anchor doesn't contribute to its parent's height (same as the old
fixed element didn't), so no other view's bottom-nav clearance math
needs to change.
Shorten the two comments added by the sticky fix to a plain why,
instead of narrating the debugging steps that found the bug.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant