dvh (Dynamic Viewport Height) is a modern CSS unit that adapts to the currently visible height of the browser viewport. It sounds like a small detail, but in practice it fixes a bug almost every web developer has run into.

If you've ever built a full-screen hero section and watched the browser's address bar cut off the bottom of it on mobile — or seen a stray scrollbar appear on a page designed to fit exactly one screen — this one's for you.

Why 100vh caused problems

By definition, vh is one percent of the viewport height. On desktop that's unambiguous: the browser window's content area doesn't change as you scroll.

On mobile it does. The address bar and the bottom navigation controls collapse as you scroll down and reappear as you scroll up, so the visible area is constantly moving. Browsers had to decide what vh should mean in that situation, and most of them chose to lock it to the largest possible value — the one you get once the browser chrome has fully collapsed.

That had a few very visible consequences:

  • a height: 100vh section extends below the screen on first load,
  • a layout designed to be exactly one screen tall becomes scrollable anyway,
  • the button or scroll cue placed at the bottom of the hero slides out of view.

For years we worked around it: measure the real height in JavaScript, write it into a custom property (--vh), then multiply it back with calc(). It worked, but it solved a layout problem with runtime code.

The new family of viewport units

CSS no longer knows just one viewport height — it knows three, because on mobile there really are three sensible answers to the question "how big is the screen?"

  • svh (small viewport height) — the smallest visible height, i.e. when all the browser UI is showing.
  • lvh (large viewport height) — the largest visible height, once the address bar and navigation have collapsed. This is what most browsers report as vh.
  • dvh (dynamic viewport height) — the current value, which tracks the browser chrome as it moves.

So 100dvh isn't a fixed number — it's a live value, always equal to the space that's genuinely available right now.

vh tells you how big the screen can be. dvh tells you how big it is.

The most common case: the hero section

The basic usage is exactly as simple as it looks:

.hero {
    min-height: 100dvh;
}

There are two small but important details in those three lines. First, min-height rather than height: if the content ever grows taller than one screen it flows on instead of being clipped. Second, dvh already gives the correct result on its own wherever it's supported.

If you still need to serve older browsers, the fallback is one extra line. CSS applies the last declaration it understands, so a browser that doesn't know dvh simply skips the second one:

.hero {
    min-height: 100vh;  /* older browsers */
    min-height: 100dvh; /* everyone else */
}

No @supports, no JavaScript, no build step required.

Which one should you use?

dvh isn't a universal answer — it depends on what you're building. A simple way to decide, which covers most cases:

  • dvh — when the element should fill the visible area and it's fine for its size to change: hero sections, full-screen slides, side drawers.
  • svh — when the element must never overflow: fixed bottom bars, sticky CTAs, app-like mobile interfaces where the bottom button always has to be reachable.
  • lvh — rarely needed, mostly when you're deliberately designing to the maximum height and overflow is acceptable.

A good rule of thumb: dvh for design, svh for guarantees. If something must always be visible, don't leave it to the dynamic value.

Not just height

The same logic runs through all the viewport units, not only height. Each one gained an s, l and d prefix:

  • dvw — dynamic viewport width,
  • dvmin and dvmax — the smaller and the larger of the two,
  • dvi and dvb — inline and block size, independent of writing mode.

In practice dvh is the reason the family exists — width changes far less often mid-scroll on mobile.

What to watch out for

The strength of dvh is also its limitation: the value genuinely changes while you scroll, and the browser has to re-run layout because of it.

Don't animate it

If a height expressed in dvh has a CSS transition on it, every movement of the browser chrome kicks off an animation. The result is a jumpy, stuttering layout. Keep the size change instant here.

Mind the content shift

If a 100dvh block sits in the middle of a long page, its height — and with it the position of everything after it — moves as you scroll. Put full-screen sections near the top of the page, or use svh further down.

The keyboard is a separate problem

On mobile, the on-screen keyboard isn't counted in the viewport height by every browser. If you need a stable layout while a form field has focus, dvh alone won't get you there — that's what the interactive-widget viewport setting or the Visual Viewport API is for.

Browser support

Dynamic viewport units have been supported by every major browser since Safari 15.4, Chrome 108, Edge 108 and Firefox 101. In 2026 that effectively covers the entire active user base, and the two-line vh fallback above takes care of the rest.

If you've been carrying a JavaScript --vh workaround, you can safely delete it: the native unit is more accurate, faster, and doesn't flash before first paint.

Frequently asked questions

What is the difference between vh and dvh?

vh measures the viewport height, but on mobile browsers it doesn't follow the address bar and navigation controls as they move — most browsers lock it to the largest possible height. dvh adapts dynamically to the area that is actually visible, so it stays accurate while you scroll.

When should I use dvh?

It's ideal for full-screen hero sections, landing pages, mobile web applications, and any layout that should match the visible screen height. For fixed elements such as bottom bars or sticky CTAs, svh is often the safer choice, because it never promises more room than there really is.

Do modern browsers support dvh?

Yes. Modern versions of Chrome, Edge, Firefox and Safari all support the dvh unit. For older browsers a simple vh fallback is enough: declare the vh rule first, then the dvh one below it.