Stabilize your mobile web layouts in 60 seconds. Solve jumping bottom menus, broken popups, and the "100vh lie" on iOS Safari, Chrome, and Firefox using modern CSS Dynamic Viewport units (dvh) and a robust shell architecture.
#iOS#Safari#NextJS#TailwindCSS#WebDev#PWA#MobileUX#Frontend
A professional, drop-in solution for Next.js 15+ and Tailwind CSS 4+ projects to solve "jumping" layouts, detached bottom menus, and broken popups on iOS browsers (Safari, Chrome, Firefox).
Add viewportFit: 'cover' to your viewport config and wrap your app in the Flexbox Shell.
// app/layout.tsximport{Viewport}from"next";exportconstviewport: Viewport={width: "device-width",initialScale: 1,viewportFit: 'cover',// Required to handle iPhone notches and toolbars};exportdefaultfunctionRootLayout({ children }: {children: React.ReactNode}){return(<htmllang="en">{/* h-dvh: Dynamic Viewport Height (responsive to keyboard) overflow-hidden: Prevents the entire page from scrolling/bouncing */}<bodyclassName="h-dvh overflow-hidden flex flex-col bg-white">{/* FIXED HEADER */}<headerclassName="flex-none p-4 border-b">Header (Static)</header>{/* SCROLLABLE CONTENT (The Magic Box) */}<divclassName="flex-1 overflow-y-auto overscroll-contain [WebkitOverflowScrolling:touch]"><mainclassName="min-h-full">{children}</main><footerclassName="p-8 border-t bg-zinc-50">Footer (Inside Scroll)</footer></div></body></html>);}Lock the body height and disable the "rubber-banding" effect.
/* globals.css */@import"tailwindcss";
html,body {
max-width:100dvw;
overflow-x: hidden;
width:100%;
}
body {
/* h-dvh adapts to the virtual keyboard and Safari toolbars! */height:100dvh; overflow: hidden;
position: relative;
overscroll-behavior: none; /* Disables page bounce */
}On iOS Safari, the browser toolbars are dynamic. When you use 100vh, the UI often gets "pushed" or buttons at the bottom become unclickable/hidden under the toolbar.
This solution provides:
- No Layout Jumps: When the keyboard opens, the
dvhunit recalculates, and only the internal content area shrinks. Headers stay at the top, and bottom-docked elements stay visible. - Safe Area Support: Uses
viewportFit: 'cover'to ensure your app background covers the area behind the notch. - Native Feel: Disables the annoying "page bounce" (rubber-banding) using
overscroll-behavior: none. - Universal Compatibility: Works on Safari, Chrome, and Firefox for iOS (all use WebKit).
- Next.js 15+
- Tailwind CSS 4+
- TypeScript 5+
MIT