Learn

/

Viewport Units

Viewport Units

5 patterns

vw, vh, dvh, svh, and lvh. Understanding the mobile viewport trap and picking the right unit. You'll hit this when a full-screen hero section hides behind the mobile browser toolbar.

Avoid
.hero {
  height: 100vh;
}
.hero {
  height: 100vh;
}

Prefer
.hero {
  height: 100dvh;
}
.hero {
  height: 100dvh;
}
Why avoid

On mobile Safari and Chrome, 100vh is taller than the visible area because it includes the space behind the collapsible URL bar. Users see a cut-off hero section and can't reach content at the bottom without scrolling.

Why prefer

100vh on mobile includes the area behind the browser's URL bar, so content gets hidden. 100dvh (dynamic viewport height) adjusts when the browser chrome appears or disappears, giving you the actual visible height.

web.dev: New viewport units
Avoid
.sticky-footer {
  position: fixed;
  bottom: 0;
  /* Uses dvh for bottom positioning */
  height: calc(100dvh - 60px);
}
.sticky-footer {
  position: fixed;
  bottom: 0;
  /* Uses dvh for bottom positioning */
  height: calc(100dvh - 60px);
}

Prefer
.sticky-footer {
  position: fixed;
  bottom: 0;
  /* svh = smallest viewport height (URL bar expanded) */
  height: calc(100svh - 60px);
}
.sticky-footer {
  position: fixed;
  bottom: 0;
  /* svh = smallest viewport height (URL bar expanded) */
  height: calc(100svh - 60px);
}
Why avoid

dvh changes as the browser chrome animates in and out, causing the fixed footer's height to constantly resize as the user scrolls. svh gives a stable value based on the smallest viewport state.

Why prefer

svh (small viewport height) is the viewport with all browser chrome visible, meaning it's the smallest the viewport can be. For fixed elements, this prevents content from jumping when the URL bar collapses. Use dvh for full-screen heroes, svh for fixed/sticky UI.

MDN: Viewport-relative units
Avoid
.hero {
  height: 100dvh;
}
.hero {
  height: 100dvh;
}

Prefer
.hero {
  height: 100vh;
  height: 100dvh;
}
.hero {
  height: 100vh;
  height: 100dvh;
}
Why avoid

While dvh has good browser support now, older browsers and some WebViews still don't support it. Without a vh fallback, the hero gets no height at all in unsupported browsers and just collapses to content height.

Why prefer

CSS cascade lets you declare 100vh first as a fallback for older browsers, then 100dvh which modern browsers will use. Browsers that don't understand dvh ignore the second declaration and keep 100vh. This is progressive enhancement in one rule.

Can I Use: Viewport unit variants
Avoid
.container {
  width: 90vw;
  margin: 0 auto;
}
.container {
  width: 90vw;
  margin: 0 auto;
}

Prefer
.container {
  width: min(90%, 1200px);
  margin-inline: auto;
}
.container {
  width: min(90%, 1200px);
  margin-inline: auto;
}
Why avoid

90vw always refers to the viewport, even inside a nested container. If this .container is inside a 50%-width sidebar, it will overflow because 90vw is relative to the full screen, not the parent. Percentage-based widths respect the parent.

Why prefer

min(90%, 1200px) caps the container at 1200px on large screens while staying 90% wide on small screens, and no media query is needed. Using % instead of vw also respects parent constraints if the container is nested, and margin-inline is the logical property equivalent.

MDN: min()
Avoid
.page-section {
  min-height: 100vh;
  scroll-snap-align: start;
}

/* Scrollbar causes horizontal overflow */
.page {
  width: 100vw;
}
.page-section {
  min-height: 100vh;
  scroll-snap-align: start;
}

/* Scrollbar causes horizontal overflow */
.page {
  width: 100vw;
}

Prefer
.page-section {
  min-height: 100dvh;
  scroll-snap-align: start;
}

.page {
  width: 100%;
}
.page-section {
  min-height: 100dvh;
  scroll-snap-align: start;
}

.page {
  width: 100%;
}
Why avoid

100vw is the full viewport including the scrollbar (typically 15-17px on Windows). This creates a horizontal overflow that's invisible on macOS (overlay scrollbar) but breaks the layout on Windows. Never use 100vw for full-width elements.

Why prefer

100vw includes the scrollbar width on Windows/Linux, causing a horizontal scrollbar. 100% refers to the containing block's width, which excludes the scrollbar. For section heights, 100dvh gives the correct visible area on mobile.

MDN: vw unit