Back

Understanding Dynamic Viewport Units in CSS

Understanding Dynamic Viewport Units in CSS

If you’ve ever built a full-screen layout on mobile and noticed content getting clipped behind the browser’s address bar, you’ve hit the classic 100vh problem. The fix used to involve JavaScript hacks. Now, CSS handles it natively with modern viewport units: svh, lvh, and dvh.

Key Takeaways

  • The traditional vh unit maps to the large viewport on mobile, causing content to overflow when the browser’s address bar is visible.
  • CSS now defines three viewport states—large (lvh), small (svh), and dynamic (dvh)—each with its own set of units.
  • Use svh for above-the-fold content, lvh for immersive full-screen layouts, and dvh for adaptive designs that respond to browser UI changes.
  • Dynamic viewport units do not account for virtual keyboards; test input-heavy layouts on real devices.
  • Always include a vh fallback for older browsers that don’t support the newer units.

Why vh Fails on Mobile

On desktop, vh works reliably. On mobile, the browser’s UI—address bar, tab strip, navigation controls—expands and collapses as users scroll. The viewport height changes, but vh doesn’t follow it.

vh reflects the large viewport (similar to lvh), which assumes browser chrome is fully retracted. So when the address bar is visible, a 100vh element can overflow the visible area. Content gets cut off, buttons become unreachable, and layouts break.

The Three Viewport States: Large, Small, and Dynamic

The CSS Values and Units specification defines three distinct viewport states to address this:

  • Large viewport — measured when all browser UI is retracted (maximum available height)
  • Small viewport — measured when all browser UI is expanded (minimum available height)
  • Dynamic viewport — tracks whichever state is currently active

Each state has a corresponding set of CSS units:

Viewport StateHeight UnitWidth Unit
Largelvhlvw
Smallsvhsvw
Dynamicdvhdvw

Each family also includes min, max, inline, and block variants (dvi, dvb, svmin, lvmax, etc.).

Important: vh effectively maps to lvh in modern browsers. They both reflect the large viewport size.

On desktop browsers without dynamic UI, all three viewport sizes are identical.

When to Use svh, lvh, and dvh

Use svh when content must stay fully visible on initial page load, before any scrolling occurs. It guarantees your layout fits within the smallest possible viewport—browser chrome fully visible.

/* Content always visible on load, no scrolling required */
.above-the-fold {
  min-height: 100svh;
}

Use lvh for immersive, full-screen experiences—games, splash screens, or app shells—where you want to fill the maximum available space.

/* Fills screen when browser chrome is hidden */
.fullscreen-app {
  height: 100lvh;
}

Use dvh when you want the layout to adapt as the browser UI changes. It’s the most practical choice for most responsive layouts.

/* Problematic on mobile */
.hero { height: 100vh; }

/* Adapts to browser chrome changes */
.hero {
  height: 100vh;   /* Fallback for older browsers */
  height: 100dvh;  /* Modern browsers use this */
}

The fallback pattern above works because browsers that don’t recognize dvh will ignore the second declaration and apply the first. Modern browsers apply the last valid declaration, so 100dvh takes effect.

The Virtual Keyboard Caveat

dvh handles address-bar resizing, but not virtual keyboards. When a user taps an input field and the on-screen keyboard appears, viewport units usually don’t adjust because most browsers resize only the visual viewport by default.

To opt in to keyboard-aware layout behavior, you can use the interactive-widget meta tag:

<meta name="viewport" content="width=device-width, initial-scale=1, interactive-widget=resizes-content">

The resizes-content value tells the browser to resize the viewport when the virtual keyboard opens. Other values include resizes-visual (the default, which only resizes the visual viewport) and overlays-content (the keyboard overlays without resizing anything). Support for this behavior currently exists mainly in Chromium-based browsers.

Chrome also offers programmatic control via the VirtualKeyboard API. Cross-browser support for that API remains limited, so if your layout depends on visible space below an input, test carefully on real devices.

Browser Support

svh, lvh, and dvh are supported in:

  • Chrome 108+
  • Safari 15.4+
  • Firefox 101+

Coverage is solid across modern browsers. The height: 100vh fallback pattern shown above handles older environments gracefully. You can also verify current compatibility on MDN’s viewport unit documentation.

Choosing the Right Unit

  • Content must fit on initial load?svh
  • Immersive full-screen layout?lvh
  • Adaptive layout that responds to browser UI?dvh
  • Supporting older browsers? → Always include a vh fallback

Conclusion

The mobile viewport height problem in CSS now has a clean, native solution. Swap vh for dvh in most cases, use svh when above-the-fold visibility matters, and reserve lvh for full-screen experiences. Always pair newer units with a vh fallback for backward compatibility, and remember that virtual keyboards require separate handling. No JavaScript required.

FAQs

Yes, but be cautious. Because dvh changes as the browser UI expands or collapses, a fixed element sized with dvh may visibly shift during scrolling. For sticky headers or footers with a fixed height, using static pixel or rem values is usually more predictable. Reserve dvh for full-height containers rather than small fixed-size elements.

The performance impact is negligible for most layouts. However, if you apply dvh to many deeply nested elements that trigger complex layout recalculations, you could see minor jank on low-end devices. Profile on real hardware if performance is critical.

They follow the same logic but apply to viewport width. On most mobile browsers, the width does not change when the address bar appears or disappears, so svw, lvw, and dvw typically return the same value. The distinction matters more on devices or browsers where side panels or other UI elements affect available width.

Add interactive-widget=resizes-content to your viewport meta tag. This tells the browser to shrink the layout viewport when the keyboard opens, which means dvh will reflect the reduced space. Without this setting, the keyboard overlays content and viewport units remain unchanged. Test on real devices since behavior varies across browsers and platforms.

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay