A hero section set to height: 100vh fills the screen perfectly in the browser devtools mobile simulator, then ends up cut off at the bottom once tested on a real phone, hidden under the browser's address bar. That mismatch has long been one of the most reported traps in responsive design, and it comes down to how vh used to be calculated.
Newer units, added specifically to fix that problem, now make it possible to choose exactly how a height should react to that bar appearing or disappearing.
Definition
vh and vw each equal one hundredth of the height, respectively the width, of the visible window. vmin takes the smaller of the two dimensions, vmax the larger, which makes them useful for a size that needs to adapt to both portrait and landscape orientation.
.banner {
height: 100vh; /* the full height of the visible window */
width: 100vw; /* its full width */
font-size: 5vmin; /* adapts to whichever dimension is smaller */
}These units belong to the wider family of CSS units, alongside the percentage and the rem, but stand apart on one point: they are always computed against the browser window, never against a parent element, which makes them useful even on an element whose own parent has no defined size at all.
The historic 100vh mobile trap
On mobile, the browser's address bar appears and disappears depending on whether the page is scrolling, which changes the height actually visible on screen. Browsers long calculated 100vh against the total height, bar hidden, rather than against the height immediately visible, bar shown. The result: a section meant to fill the whole screen would consistently overflow at the bottom on first load, before the user scrolled the page.
The newer units that fix the problem
| Unit | Based on |
|---|---|
svh (small viewport height) | The smallest possible height, address bar always shown |
lvh (large viewport height) | The largest possible height, bar hidden: the old 100vh behaviour |
dvh (dynamic viewport height) | The actual current height, recalculated live during scrolling |
.banner {
height: 100vh; /* fallback for older browsers */
height: 100dvh; /* overrides the line above wherever supported */
}dvh recalculates the height in real time as the address bar appears or disappears, which can create a small visible jump while scrolling. For content that should never move, svh stays the most stable choice, even if it means leaving a temporary blank strip when the bar hides.Typical use cases
A full-screen hero section benefits from dvh, to fill the height actually visible at any given moment. A critical element that must never be cut off, like an action button pinned to the bottom of the screen, benefits instead from svh, the most conservative of the three. These units pair well with aspect-ratio for sections that need to keep precise proportions regardless of the screen, and often serve as the threshold inside a Media query when the layout needs to change based on visible height rather than width.
Frequently asked questions
100vh and 100% always give the same result?No, % is computed against the size of the parent, which may itself not fill the whole window if its own height is not set. vh is always computed against the window itself, independently of the chain of parents.
100vh be replaced with 100dvh?Not urgently, but it is recommended for full-screen sections shown on mobile. Good practice is to keep height: 100vh; first as a fallback, then add height: 100dvh; right after: a browser that does not recognise that value simply ignores the line, without breaking the previous one.
Yes, broadly, across modern browsers for several years now. Keeping a plain vh fallback is still good practice for visitors on an older browser.