Safari 100vh bug: the address bar, dvh, svh and lvh (iOS 26)

Why 100vh overflows on iPhone, the three viewport units that replace it, which one to pick for each layout, and the iOS 26 toolbar details nobody has written down yet.

Updated 4 min read

SafariiPhone 17 Pro · 402 × 874
iPhone 17 Pro in Safari, with dimension lines on the top and bottom bars

Short answer: in Safari on iPhone, 100vh is the height of the screen with the toolbar hidden. When the page loads, the toolbar is showing, so a 100vh block is taller than what you see and its bottom ends up behind the bar. Use 100svh for things that must fit on the first screen, 100dvh only for app shells that should follow the toolbar, and keep 100vh as the fallback line.

.hero {
  min-height: 100vh;  /* fallback for browsers before 2022 */
  min-height: 100svh; /* fits with the toolbar showing */
}

That’s not a bug Apple will fix. The WebKit report about it has been open since 2015, and the behavior is now written into the CSS spec.

Why 100vh is taller than the screen

Mobile browsers have three heights for the same screen:

  • Small viewport (svh): the toolbar is fully showing. This is what you see when the page first loads.
  • Large viewport (lvh): the toolbar has collapsed after you scroll down.
  • Dynamic viewport (dvh): whichever of the two is true right now, changing as the toolbar moves.

The CSS Values 4 spec says plain vh maps to the large viewport, for web compatibility. Safari does that, and so does Chrome on Android. So 100vh = 100lvh, which is taller than the screen you actually see at load time.

On an iPhone 16 Pro or 17 Pro in iOS 26, with the default Compact tab layout, window.innerHeight measures 718 px with the toolbar expanded and 754 px collapsed. A 100vh hero is roughly 36 px taller than what’s visible on load, which is exactly enough to hide a “scroll down” arrow or a bottom button.

Which unit to use

Layout Use Why
Hero, landing first screen, splash min-height: 100svh Always fits with the toolbar showing; never resizes while scrolling
Full-screen background image 100lvh Covers the screen even when the toolbar collapses, no gap
App shell, chat, map with a fixed composer height: 100dvh Follows the toolbar so the bottom row stays visible
Full-screen overlay or modal position: fixed; inset: 0 Matches the visible area without any unit
Long scrolling page Avoid dvh Its height changes while the user scrolls, causing reflows and jank

Support for svh, lvh and dvh covers Safari 15.4+, Chrome and Edge 108+, Firefox 101+ and Samsung Internet 21+, about 96% of users. Writing 100vh first and the new unit second is enough of a fallback; @supports is optional.

.app {
  height: 100vh;
  height: 100dvh;
  display: grid;
  grid-template-rows: auto 1fr auto; /* header, scroll area, composer */
}
.app main { overflow-y: auto; }

Stop using the old hacks

  • height: -webkit-fill-available only worked in WebKit, breaks in Chrome, and has not been needed since Safari 15.4 (March 2022).
  • The JS --vh trick (document.documentElement.style.setProperty('--vh', innerHeight * 0.01 + 'px') on resize) was the fix for Safari before 15.4. Today it’s slower and less accurate than svh or dvh. Remove it unless you still support iOS 15.3 or older.

What changed in iOS 26

iOS 26 brought the Liquid Glass design to Safari: in the default Compact layout, the tab bar floats at the bottom and the page scrolls underneath it. A few things follow from that.

  • Content can sit under the toolbar. With viewport-fit=cover in your viewport meta, the page extends under the glass bar. Give fixed bottom elements padding-bottom: env(safe-area-inset-bottom) or the bar covers them.
  • theme-color no longer tints the bar. Safari 26 tints the toolbar from your page: the html/body background and fixed or sticky elements near the top and bottom edges. Set an explicit html { background: … }, and hide closed overlays with display: none (an opacity: 0 overlay still tints the bar).
  • Early 26.x bugs were fixed. Safari 26.1 fixed a gap at the bottom of layouts with viewport-sized fixed containers; 26.2 made full-screen <dialog> backdrops extend below the address bar and stopped edge-pinned fixed elements from vanishing during rubber-band scrolling. If you added workarounds in September 2025, retest them.

A fixed bottom bar that works with both the toolbar and the home indicator:

<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
html { background: #fff; }
.tab-bar {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  padding-bottom: max(env(safe-area-inset-bottom), 12px);
  background: #fff; /* solid: also what Safari 26 samples for the tint */
}

More on insets in why safe-area-inset-bottom is not working.

The keyboard doesn’t change dvh

People expect 100dvh to shrink when the on-screen keyboard opens. It doesn’t, on iOS or on Chrome for Android since version 108: the keyboard only resizes the visual viewport, and viewport units stay the same. To keep a composer above the keyboard, listen to visualViewport:

const vv = window.visualViewport;
const update = () => {
  const keyboard = Math.max(0, innerHeight - vv.height - vv.offsetTop);
  document.documentElement.style.setProperty('--keyboard', keyboard + 'px');
};
vv.addEventListener('resize', update);
vv.addEventListener('scroll', update);
.composer { bottom: var(--keyboard, 0px); }

On Android you can opt back into the old behavior with interactive-widget=resizes-content in the viewport meta. Safari ignores that key.

How to test it

  • Real iPhone: the only way to see the toolbar collapse, the keyboard and the rubber band. Load the page, check the first screen, scroll down a little, check again, then focus an input.
  • DevTools device mode: shows a fixed viewport with no toolbar, so 100vh, svh and dvh are all equal. It can’t show this bug.
  • Breakpane: draws the iOS 26 Safari toolbar (and Chrome’s on Android) around a viewport the size Safari reports with the toolbar expanded, on Windows or macOS. That’s the check for the result: does your first screen fit, and is anything hidden behind the bar or the home indicator. The toolbar doesn’t collapse and it renders with Chromium, so vh, svh and dvh are equal there and it won’t reproduce the overflow itself. Do the scroll and keyboard pass on a real iPhone.

Other guides

  1. PWAiPhone 17 Pro · 402 × 874
    iPhone 17 Pro home screen with an installed PWA icon
    How to test a PWA on iPhone (and from localhost)
  2. Safe areaiPhone 17 Pro · 402 × 874
    iPhone 17 Pro running a full-screen web app, with safe area dimension lines
    env(safe-area-inset-bottom) not working? Every cause and fix
  3. iPhoneiPhone Air · 420 × 912
    iPhone Air running a web app in dark mode, with the width dimension line
    iPhone simulator for Windows? How to test a website on iPhone without a Mac