Problem
On iOS Chrome (26), my position: fixed; bottom: 0 tab bar and position: sticky; top: 0 header both scroll with the page content instead of staying
pinned. The entire viewport appears to shift — fixed/sticky elements move together with the content when the browser's bottom toolbar collapses during
scroll.
Key observations
- Only affects certain pages — /product/*, /shop, /cart work perfectly fine, even on first load
- First load only — if I reload the page, the bug sometimes persists. But after navigating to a working page (e.g. /product/...) via client-side
navigation and coming back, the bug disappears permanently for that session - Opening a working page in another tab in the same incognito session fixes the bug for all tabs
- Not reproducible in desktop browsers or Playwright (WebKit emulation)
- Not reproducible in iOS Safari
What I've tried (none worked)
CSS approaches:
- transform: translateZ(0) / will-change: transform on the fixed element
- position: sticky instead of position: fixed
- top: calc(100dvh - height) instead of bottom: 0
- overflow-x: clip / overflow-x: hidden on body
- overscroll-behavior-y: none on html/body
- scroll-behavior: auto instead of smooth on mobile
- viewport-fit=cover in viewport meta tag
- min-height: 100dvh / 200vh on content containers
JS approaches:
- window.visualViewport resize/scroll listeners adjusting bottom or top
- window.scrollTo(0,1); window.scrollTo(0,0) to force viewport recalculation
Nuxt/Vue approaches:
- Disabling pageTransition
- Removing await from useAsyncData (non-blocking)
- Replacing defineAsyncComponent with eager imports
- Client-only rendering (definePageMeta({ ssr: false }))
- Moving all logic into a child component (like working pages do)
- Wrapping layout in flex container
DOM investigation:
- Scroll event listener on document (capture) shows scroll target is document — no nested scroll container
- Safari Web Inspector computed styles for body, html, .tab-bar are identical between working and broken pages
- No transform, filter, contain, or overflow on any ancestor that could break fixed positioning
Environment
- iOS latest version, Chrome for iOS
- Nuxt 3 with SSR
- Layout: sticky header + scrollable content + fixed bottom tab bar
Working vs broken pages
All pages share the same layout (position: sticky header, position: fixed tab bar). The only difference is the page component content. Even a clone of
the broken page at a different URL reproduces the bug.
Broken pages have useAsyncData fetching content from an API and rendering dynamic blocks. Working pages (/shop, /cart) either have no useAsyncData or
render static component trees. However, /product also uses useAsyncData and works fine.
Replacing dynamic rendering with static components, hardcoded data, or client-only rendering did NOT fix the issue.
Question
What could cause iOS Chrome to render position: fixed and position: sticky elements as if they're scrolling with the page, only on specific pages, and
only on the first load of a session? Is there a known iOS Chrome/WebKit behavior that causes this?
Code:
.tab-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
width: 100%;
max-width: 100%;
z-index: 9;
background-color: $dark;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 1.25rem;
border-top: 1px solid $gray_4;
height: 4.375rem;
Screens:
https://gyazo.com/6f5981a7e2de00063dbe41c506d992f3
https://gyazo.com/8cfa4122dff2990f8721ccdadff770ad