ARTICLE AD BOX
I'm building a Nuxt 4 PWA installed via Safari "Add to Home Screen" on iOS. The app has a bottom navigation bar that should sit flush against the bottom of the screen, filling the home indicator (safe area) zone with its background. Instead, there's a visible white gap between the bottom nav and the physical screen edge.
Setup
Viewport meta tag:
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, user-scalable=no">Apple PWA meta tags:
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">PWA manifest uses "display": "standalone".
CSS (base layer):
:root { --safe-area-top: env(safe-area-inset-top, 0px); --safe-area-bottom: env(safe-area-inset-bottom, 0px); --safe-area-left: env(safe-area-inset-left, 0px); --safe-area-right: env(safe-area-inset-right, 0px); } html { overflow: hidden; } body { padding-left: var(--safe-area-left); padding-right: var(--safe-area-right); overscroll-behavior: none; overflow: hidden; margin: 0; }Layout (wraps all pages):
<div class="h-[100dvh] bg-white flex flex-col overflow-hidden"> <main class="flex-1 overflow-hidden"> <!-- page content (each page has its own scrollable area) --> </main> <BottomNav /> </div>Bottom navigation CSS:
.bottom-nav { background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(12px); border-top: 1px solid #e5e7eb; display: flex; justify-content: space-around; align-items: center; z-index: 30; flex-shrink: 0; padding-bottom: max(12px, env(safe-area-inset-bottom)); padding-top: 8px; }The BottomNav is a flex child (not position: fixed) within the h-[100dvh] flex container. It uses padding-bottom: max(12px, env(safe-area-inset-bottom)) to push its content above the home indicator while filling the safe area with its background.
The problem
On iOS standalone PWA (Add to Home Screen), 100dvh appears to resolve to the viewport excluding the bottom safe area inset (~34px on iPhones with the home indicator). This means the entire flex layout — including the BottomNav and its safe area padding — is contained within a box that's ~34px shorter than the physical screen. The result is a white gap between the bottom of the nav and the screen edge.
What I've tried
body { padding-bottom: env(safe-area-inset-bottom) } — Fills the gap with the body background, but now the layout's 100dvh exceeds the body content area, and adding overflow: hidden clips it. Removing overflow allows body scrolling which breaks the fixed header.
body { position: fixed; inset: 0 } — On WebKit, a position: fixed body still resolves height: 100% to the safe-area viewport, not the full physical screen. Same gap.
position: fixed; inset: 0 on the Nuxt wrapper div (#__nuxt) — Same result.
position: fixed; inset: 0 directly on the layout root div — This fills the screen correctly but then percentage-based heights (h-full) on child pages don't resolve because Nuxt inserts intermediate wrappers (Suspense, router-view) without explicit heights.
height: -webkit-fill-available on html/body — No effect in standalone PWA.
min-h-screen instead of h-[100dvh] on layout — 100vh on iOS has the same problem in standalone mode. Also causes page headers to scroll with content instead of staying fixed.
Desired behavior
The app should fill the entire physical screen edge-to-edge. The BottomNav's padding-bottom: max(12px, env(safe-area-inset-bottom)) should extend its background into the home indicator area so there's no visible gap. The header should remain fixed at the top, and only the content area between header and nav should scroll.
Environment
iOS 26 (iPhone with home indicator) Safari → Add to Home Screen (standalone PWA) Nuxt 4 (^4.3.0) with @vite-pwa/nuxt Tailwind CSSHow do I make 100dvh (or any CSS approach) fill the full physical screen in an iOS standalone PWA with viewport-fit=cover?
