Dynamic Viewport Units: dvh, svh, and lvh Explained
dvh, svh, and lvh fix the classic mobile vh bug where browser toolbars cut off full-height layouts. Here's what each unit measures and when to use it.
Dynamic viewport units — dvh and dvw, along with their svh/lvh and svw/lvw siblings — are CSS length units that account for a browser’s shifting UI chrome, like a mobile address bar that collapses as you scroll. They exist to fix a specific, long-standing annoyance: 100vh on a phone doesn’t mean what most developers assume it means.
The vh problem on mobile
100vh was defined against the layout viewport — the full area a page can occupy, independent of whatever browser UI happens to be showing. On desktop that’s close enough to what you see. On mobile it isn’t. When a page first loads, the address bar and tab strip are visible, so 100vh reports a shorter height than the screen. Scroll down a little and many mobile browsers collapse that chrome to give you more room — but 100vh doesn’t shrink to fill the new space, and it doesn’t grow either. The result is a footer that’s cut off below the fold, or a full-screen hero section with a visible gap at the bottom, depending on which state the browser happened to be in when the CSS was computed.
For years the only reliable fix was JavaScript: read window.innerHeight, write it to a custom property, and update it on resize and scroll. It worked, but it meant a layout-critical value depended on script execution instead of the critical rendering path alone.
Three viewport states: small, large, dynamic
Dynamic viewport units give CSS native vocabulary for the states that used to require JavaScript:
| Unit | What it measures | Changes as you scroll? |
|---|---|---|
svh / svw | Smallest possible viewport — browser UI fully expanded | No, fixed at the minimum |
lvh / lvw | Largest possible viewport — browser UI fully collapsed | No, fixed at the maximum |
dvh / dvw | Whatever the viewport actually is right now | Yes, recalculates live |
svh and lvh are static: the browser picks the value once, based on the smallest or largest the viewport could ever be, and it doesn’t move after that. dvh is the one that actually tracks reality — it recomputes as the address bar shows and hides, so a min-height: 100dvh element genuinely fills the visible screen at every scroll position.
Using dvh in practice
The most common use is a full-bleed hero or landing section that needs to fill the screen without leaving a gap or forcing a scrollbar:
.hero {
min-height: 100dvh;
display: grid;
place-items: center;
}
That single line replaces the old JavaScript-plus-custom-property workaround for most cases. It’s worth knowing the tradeoff, though: because dvh recalculates as the browser’s chrome animates in and out, an element sized with it can resize mid-scroll, which forces the browser to reflow. For a hero section that’s fine — the resize is expected and looks natural. For something that shouldn’t visibly shift, like a fixed modal or a sticky footer, svh is usually the better choice, since it commits to the smallest viewport up front and never moves under you.
A practical pattern: use lvh for elements you want sized generously (so they don’t feel cramped once the browser chrome collapses), svh for anything that must never overflow the visible area even in the worst case, and dvh only where a live-tracking, occasionally-shifting size is actually the desired behavior.
Fallbacks and browser support
Dynamic viewport units are supported in all current major browser engines, but if you need to support older ones, declare the fallback first — CSS uses the last valid declaration it understands, so an unsupported unit simply gets skipped rather than breaking the cascade:
.hero {
min-height: 100vh; /* fallback for older engines */
min-height: 100dvh; /* used where supported */
}
This avoids a @supports block entirely: browsers that don’t recognize dvh as a unit ignore that declaration and keep the vh one above it.
Where this fits with other viewport-relative sizing
Dynamic viewport units solve a height problem, not a general responsive-sizing problem — they’re a complement to, not a replacement for, tools like clamp() for fluid typography or container queries for component-level responsiveness. vw, vh, vmin, and vmax all still have their place; dvh and friends just make the height-based ones trustworthy on mobile. If you’re deciding between viewport units and other relative units for a given property, see rem vs. em vs. px for how those tradeoffs generally play out. And for elements that need to hold a fixed proportion rather than fill the screen, aspect-ratio is usually a better fit than any viewport unit at all — it sizes relative to an element’s own width instead of the window.
The takeaway
100vh measures the layout viewport, which mobile browsers don’t keep in sync with what’s actually visible on screen. svh and lvh give you the smallest and largest possible viewport as fixed values; dvh tracks the real, currently-visible viewport and updates as browser chrome shows and hides. Use dvh for full-bleed sections where a bit of live resizing is fine, svh for anything that must never overflow, and pair either with a vh fallback declared first for older browsers.
Tagged
Keep reading
Takina · · 4 min read CSS object-fit and object-position, Explained
object-fit controls how an image or video is cropped inside its box, and object-position controls which part of it stays visible. How they work together.
Takina · · 5 min read CSS inherit, initial, unset & revert Explained
CSS's four global keywords control where a property's value comes from. How inherit, initial, unset, and revert differ, with a comparison table.
Takina · · 4 min read CSS Grid repeat() and minmax() Explained
repeat() and minmax() let CSS Grid build responsive layouts without media queries. How the two functions combine, and common patterns.