100vh on Mobile Safari: dvh, svh and lvh Explained
Short answer: On phones, 100vh equals the largest viewport height, measured with the browser toolbars retracted, so a 100vh section is taller than the visible screen while Safari's or Chrome's bars are showing. Use 100svh for full-screen sections that must fit with the bars visible, 100dvh when an element should follow the bars as they move, and keep 100vh as a fallback for browsers older than Safari 15.4 or Chrome 108.
On a phone, 100vh is the height of the screen with the browser's toolbars hidden, not the height you actually see when the page opens. While Safari's toolbar or Chrome's address bar is showing, a 100vh hero is taller than the visible area and its bottom, often the button that matters, sits off-screen. Use 100svh when something must fit with the toolbars visible, and keep 100vh before it as a fallback.
Why is 100vh taller than the screen on mobile?
Mobile browsers shrink their interface as you scroll. Safari on iPhone collapses its toolbar, and Chrome on Android slides its address bar away, so the visible area grows by a few dozen pixels. If vh followed every change, any element sized in vh would resize during scrolling and the page would jump.
So both browsers chose a stable value: 1vh is 1% of the largest possible viewport, the one with the toolbars retracted. That avoids the jumping, but it means that on first load, when the bars are visible, 100vh is taller than the space you actually have.
Typical symptoms:
- a full-screen hero whose "Get started" button is hidden until you scroll;
- a mobile menu or modal with
height: 100vhwhose last items or close button can't be reached; - an app-style layout with a footer bar that sits below the visible area;
- a "fits exactly one screen" landing page that scrolls a little on phones.
What do svh, lvh and dvh mean?
CSS Values and Units Level 4 added three sets of viewport units so you can say which height you mean:
| Unit | 1 unit equals 1% of… | Good for |
|---|---|---|
svh (small) | the viewport with all browser bars shown | Heroes and sections that must fit on first load |
lvh (large) | the viewport with the bars retracted; what vh means on phones | Backgrounds that should never show a gap |
dvh (dynamic) | whatever is visible right now; changes as the bars move | Full-height app shells, overlays that should follow the bars |
There are matching width units (svw, lvw, dvw) and logical ones (svb, dvi and so on), but height is where the difference shows. Support arrived in Safari 15.4, Chrome 108 and Firefox 101, so current phones handle them.
Which unit should I use?
Full-screen hero: svh
A hero that should fill the first screen without hiding its call to action is the classic case. svh guarantees it fits with the bars visible; when they collapse, a little extra page shows below, which is harmless.
.hero {
min-height: 100vh; /* fallback for old browsers */
min-height: 100svh;
}
Use min-height, not height, so the hero can still grow when the text inside it wraps or the visitor enlarges text; see the overlap and clipping guide.
App shell or sticky footer layout: dvh
For a layout that should always fill exactly what is visible, such as a chat window with an input bar at the bottom, dvh tracks the toolbars:
.app {
display: grid;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
min-height: 100dvh;
}
The trade-off: the element resizes while the toolbars animate, which causes layout work during scrolling and can move content. Don't use dvh for large sections of a normal scrolling page.
Menus and modals: often no unit at all
A fixed overlay with inset: 0 usually follows the visible area without any viewport unit, and an internal scroll keeps the last items reachable:
.menu-panel {
position: fixed;
inset: 0;
overflow-y: auto;
overscroll-behavior: contain;
}
Do I still need a fallback?
Browsers ignore a declaration they don't understand and keep the previous one, so writing 100vh first and the new unit second is enough. iPhones that can't update past iOS 15 run Safari 15.x; only 15.4 and later understand the new units, and older versions use the 100vh line. If you need the two to differ more, use a feature query:
@supports not (height: 100svh) {
.hero { min-height: calc(100vh - 80px); }
}
Older workarounds such as height: -webkit-fill-available or setting a --vh custom property from window.innerHeight in JavaScript are no longer needed for current browsers. Remove them when you switch, so they don't fight the new units.
What about the on-screen keyboard?
None of the viewport units shrink for the keyboard by default. On iPhone, the keyboard covers the page and only the visual viewport gets smaller. Chrome on Android has behaved the same way since version 108; adding interactive-widget=resizes-content to the viewport tag makes Chromium browsers resize the layout for the keyboard instead. To position something just above the keyboard in any browser, read window.visualViewport.height and listen for its resize event.
On iPhone vs Android
- Safari on iPhone shows its toolbar when the page loads and collapses it as you scroll. The difference between
svhandlvhis largest here, so iPhones are where100vhbugs show up first. - Chrome on Android slides its address bar away as you scroll and also treats
vhas the large viewport, so the same bug appears, just with a smaller gap. - Home-screen web apps (
display: standalone) have no browser bars, so all the units are equal there.
How do I check it?
MobileCheck renders each device at its real width with the space taken by the browser's bars already subtracted, so the free check shows how much of a full-screen section fits on the first screen. Our emulated browsers have no toolbar that collapses, though, so vh, svh, lvh and dvh all resolve to the same height there. To see the difference, open the page on a real iPhone: load it, check that the hero's button is visible without scrolling, then scroll and watch the bottom of the screen as the toolbar collapses. The mobile viewport sizes list shows the screen heights worth testing, and the safe area guide covers the related problem of bars and the home indicator.
Frequently asked questions
Why is 100vh wrong on iPhone?
Safari defines 100vh as the height with its toolbar collapsed. When the page first loads the toolbar is visible, so a 100vh element is taller than the visible area and its bottom is hidden until you scroll.
Should I use dvh or svh?
Use svh for sections that must fit on the first screen, such as heroes. Use dvh only for app-like layouts that must always match the visible area, because dvh elements resize while the toolbars move.
Do dvh and svh work in all browsers?
They work in Safari 15.4 and later, Chrome 108 and later and Firefox 101 and later. Write a 100vh declaration first as a fallback for older browsers.
Sources
- web.dev: The large, small, and dynamic viewport units
- MDN: <length> (viewport-percentage lengths)
- W3C: CSS Values and Units Level 4, viewport-relative units
- MDN: VisualViewport API