lucky.graphics

tutorials

dvh vs svh vs vh: Which Viewport Unit to Use (2026)

Why 100vh overflows on phones, what svh, lvh and dvh measure, pixel math for a full-height hero, browser versions, and which unit to use for each job.

Published
November 13, 2026
Topic
tutorials
Reading time
22 min
Review
Reviewed against the primary source

dvh vs svh vs vh: Which Viewport Unit to Use in 2026

Use svh for in-page layout such as a full-height hero, dvh for fixed overlays that must match the visible window right now, and lvh only for backgrounds that must never show a gap. Plain vh now equals lvh in every browser, which is why a 100vh hero overflows a phone while its address bar is showing.

The fix arrived in Chrome and Edge 108, Firefox 101 and Safari 15.4, according to MDN's browser-compat-data, so every current engine has had the three new unit families for years. What most explanations skip is the arithmetic: how many pixels each unit resolves to on a phone in each toolbar state, and what that does to the button at the bottom of your hero. That arithmetic decides the unit.

Three Viewports on One Phone

CSS Values and Units Level 4 (W3C Working Draft, 12 March 2024) starts from the fact that mobile browsers have interface parts, mainly the address bar and toolbar, that slide in and out as the reader scrolls. Rather than pick one window size, the spec defines three.

  • Large viewport. The viewport sized as if those dynamic interfaces are retracted. It is the biggest the window ever gets without the reader rotating or resizing anything.
  • Small viewport. The viewport sized as if those interfaces are expanded. It is the smallest the window gets from toolbars alone, so anything sized to it fits even while the toolbars are on screen.
  • Dynamic viewport. The viewport sized "with dynamic consideration" of those interfaces, so it tracks whatever is true at the moment: small when the bars are showing, large when they have slid away.

Two properties of these definitions matter for design work. The spec says the small and large sizes are fixed, and therefore stable, unless the viewport itself is resized. And it says the dynamic sizes "are not stable even while the viewport itself is unchanged", which is a polite way of saying they change while the reader scrolls. MDN's length reference repeats the warning and adds that resizing during scroll "can lead to degradation of the user interface and cause a performance hit."

The fourth family is the one you already use. Plain vw, vh and friends are the "UA-default" viewport units. Early drafts let each browser choose what they meant. The current draft says the mapping to the large units "is presumed to be required for Web compatibility," and MDN states it as present fact: all default viewport units are equivalent to their large counterparts, so vh is lvh. That single sentence explains the 100vh problem, which the next section works through in pixels.

The spec also lists what does not count as dynamic interface. Some UI overlays the page without shifting layout, and the draft notes that on-screen keyboards typically fall in that category. A keyboard opening does not, by default, change any of these units. That gets its own section further down, because it is a separate fix.

All 24 Units on One Grid

The names follow a grid. A prefix picks the viewport (none, sv, lv or dv), and a suffix picks the measurement (w, h, i, b, min or max). Every combination exists, which gives 24 units.

SuffixMeasures 1 percent ofDefault (= large)SmallLargeDynamic
wViewport widthvwsvwlvwdvw
hViewport heightvhsvhlvhdvh
iViewport size on the element's inline axisvisvilvidvi
bViewport size on the element's block axisvbsvblvbdvb
minThe smaller of the w and h valuesvminsvminlvmindvmin
maxThe larger of the w and h valuesvmaxsvmaxlvmaxdvmax

The spec's own example for the width unit is a reminder that these are plain percentages: with an h1 set to font-size: 8vw and a viewport 200mm wide, the heading is 16mm. Nothing else is involved. The only questions are which window the percentage is taken of, and when that window is measured.

Most of the time the width column does not care about toolbars, because phone toolbars sit above and below the page rather than beside it. In portrait, svw, lvw, dvw and vw normally resolve to the same number. The height column is where the families split, so h and its logical partner b do most of the work below.

Why 100vh Overflows a Phone: The Arithmetic

Device viewport sizes vary by model, browser, zoom level and orientation, so the numbers below are an illustration, not a measurement of any phone. They are chosen to be round and plausible. Take a phone browser whose layout viewport is 390 CSS pixels wide, with these heights:

  • Large viewport (toolbars retracted): 844 px tall.
  • Small viewport (toolbars expanded): 740 px tall.
  • So the dynamic toolbars take 104 px when they are showing.

Each viewport unit is 1 percent of one of those heights:

UnitToolbars showingToolbars retractedChanges during scroll?
1vh (= 1lvh)8.44 px8.44 pxNo
1lvh8.44 px8.44 pxNo
1svh7.40 px7.40 pxNo
1dvh7.40 px8.44 pxYes

Now put a hero on the page with min-height: 100vh. On first load the toolbars are usually showing, so the reader sees 740 px of window. The hero is 844 px tall, so 104 px of it, about 12.3 percent, starts below the visible area. If the design puts its call-to-action button at the bottom of the hero, say a 48 px button with 32 px of padding underneath, the button occupies 764 px to 812 px from the top. The visible window ends at 740 px. The whole button is off screen on first load, which is precisely where the designer was sure it would be visible.

web.dev's article on the new units describes this behaviour in general terms: elements sized to 100vh "will bleed out of the viewport" while the dynamic toolbars are visible, and only cover it exactly once the toolbars retract.

Change the rule to min-height: 100svh and the hero is 740 px tall in both states. With the same 80 px of button plus padding, the button sits at 660 px to 708 px, inside the 740 px window, on first load. When the reader scrolls and the toolbars slide away, the window grows to 844 px while the hero stays at 740, so the top 104 px of the next section comes into view. That is usually what you want: a reader who is scrolling is already heading to the next section.

Change it to min-height: 100dvh and the hero is 740 px on load, matching the window, and then grows to 844 px as the toolbars retract. Everything after the hero moves down by up to 104 px while the reader's finger is on the screen. web.dev notes that browsers do not update the dynamic values at 60 frames per second: they throttle updates while the toolbars move, and some debounce them depending on the gesture. So the growth tends to happen in steps rather than smoothly.

One hero, three units, on an illustrative 390 by 844 px phoneThree hero boxes. 100vh equals 100lvh: 844 px tall, so its bottom button sits below the 740 px visible edge when toolbars show. 100svh: 740 px tall, button visible. 100dvh: 740 px while toolbars show, then grows by 104 px to 844 px when they retract during scroll.Dashed line: bottom of the visible windowwith toolbars showing (740 of 844 px)100vh = 100lvh844 px tallbutton off screen100svh740 px tallbutton visible100dvh740, then 844grows on scroll
One hero, three units, on an illustrative 390 by 844 px phoneIllustration with chosen inputs, not a device measurement: large viewport 844 px tall, small viewport 740 px, a 48 px button with 32 px of padding below it. Shaded strip: the 104 px a dvh hero gains when the toolbars retract.Source: unit definitions from W3C CSS Values and Units Level 4 (Working Draft, 12 March 2024) and MDN's length reference; pixel values are Lucky Graphics Editorial arithmetic on the stated inputs, checked November 13, 2026.
Show the data as a table
Hero height and button position by unit
RuleToolbars showingToolbars retractedButton position from top, toolbars showing
min-height: 100vh (= 100lvh)844 px844 px764 to 812 px (off screen; window ends at 740)
min-height: 100svh740 px740 px660 to 708 px (visible)
min-height: 100dvh740 px844 px660 to 708 px on load, moves down as the hero grows

The Hero Section, Settled

For a hero, intro panel, splash screen or any full-height section that sits in the normal flow of the page, the reliable rule is:

.hero {
  min-height: 100vh;   /* older browsers only */
  min-height: 100svh;  /* fits the window with toolbars showing */
}

Use min-height rather than height. A hero with a long headline, translated copy, or a reader who has set a large default text size needs to grow past one window. A fixed height clips that content or overlaps it with the next section, and the pillar guide on px, rem and em explains why text that cannot grow is an accessibility failure, not a cosmetic one.

The two-line pattern works because browsers drop a declaration they cannot parse and keep the previous valid one. A browser older than the support versions keeps 100vh; anything current uses 100svh. You can do the same with @supports (height: 100svh) if the fallback needs to differ in more than one property, and @supports itself has been in browsers since Chrome 28, Firefox 22 and Safari 9 according to the same compat data.

There are two cases where 100svh is the wrong answer for a hero. If the hero image is the point and an empty strip of the next section would look broken when the toolbars retract, give the background layer lvh while the content box stays on svh (more on that pattern below). And if you have no business reason for a full-window hero at all, consider not having one: a hero that fills the screen pushes every other piece of content below the fold, and a full-window image changes how Largest Contentful Paint picks its element, which our hero image byte budget guide works through.

The Case Against dvh for Layout in the Flow

dvh is the unit most tutorials recommend as "the fix", and for in-flow layout it is usually the one to avoid. The spec and MDN both name the problem: dynamic units change while the reader scrolls. A 100dvh section in the flow grows by the toolbar height during the scroll that retracts the toolbars, and the browser has to lay out everything after it again.

What the reader sees depends on the page. If the dvh section is the first thing on the page, the content below it moves down while the reader is trying to move it up, which reads as stutter. If several sections are each 100dvh (a common pattern for slide-style landing pages), each grows by the toolbar height, so on the illustrative phone a five-section page gets 520 px longer the moment the toolbars slide away. Scroll position stays where it was, which means the reader's place in the content jumps relative to their finger.

There is also a measurement question. Our guide to Cumulative Layout Shift worked examples quotes the Layout Instability specification: an event whose only effect is to begin or update a scroll gesture is not an excluding input. Shifts during scrolling get no grace period. Whether a given dvh resize is scored depends on scroll anchoring and on which elements move in viewport coordinates, which that guide covers in detail, so measure your own page in DevTools rather than assuming either way.

None of this makes dvh a bad unit. It is the right unit when the element is supposed to equal the visible window at all times and nothing else in the flow depends on its height. That describes overlays and app shells, not sections.

Modals, Drawers and Full-Screen Overlays

An overlay with position: fixed is out of the normal flow. When it resizes, nothing else on the page moves, so dvh's instability costs very little and its accuracy is worth having.

Take a centred modal with max-height: 90vh on the illustrative phone. That is 90 x 8.44 = 759.6 px. With the toolbars showing, the window is 740 px tall, so the modal is 19.6 px taller than the space it is supposed to fit in, and if it is centred, about 9.8 px is lost at each end (more at the bottom if it is anchored to the top). The close button in the corner of a modal is exactly the kind of control that ends up clipped.

RuleToolbars showingToolbars retractedFits both?
max-height: 90vh759.6 px (window 740)759.6 px (window 844)No, 19.6 px too tall when toolbars show
max-height: 90svh666 px666 pxYes, but leaves 178 px unused when toolbars are hidden
max-height: 90dvh666 px759.6 pxYes, uses the space available in each state

For overlays the dvh row is the useful one. A full-screen menu or drawer works the same way: height: 100dvh on a fixed panel matches the visible window as the toolbars come and go, and because the panel is fixed, the page under it does not shift. Keep svh as the fallback if you are worried about older browsers, written in the same two-line pattern (vh, then dvh), or as the main value if the overlay has an animation that would look odd resizing mid-way.

Inside the overlay, make the content area scroll rather than the whole panel: a header and footer row with fixed heights, and a middle region with overflow: auto. That way the dynamic height only changes the size of the scrolling region, and the close button and primary action stay put. Make those controls large enough to hit; our touch target size guide converts the platform minimums into CSS pixels.

Backgrounds That Must Never Show a Gap: lvh

The large units are the least used of the three, and they have one clear job. Suppose a page has a decorative background (a gradient, a photograph, a pattern) on a fixed layer behind the content. If that layer is 100svh tall, then when the toolbars retract the window becomes 104 px taller than the layer, and the reader sees a bare strip at the bottom. If it is 100dvh, it resizes during the scroll and can visibly jump.

Sized to 100lvh, the layer is always as tall as the largest the window gets. When the toolbars are showing, the bottom 104 px of it sits behind them, and since it is decoration, that costs nothing. This is the one place where the old 100vh behaviour is the behaviour you want, and writing lvh rather than vh says so on purpose, so a later developer does not "fix" it.

The rule of thumb: content goes on svh or dvh, decoration can go on lvh. If a layer has text or controls on it, it should not be on lvh.

Footers: Pushed to the Bottom, Fixed, or Sticky

"Sticky footer" means two different things, and they need different answers.

The first is a footer that sits at the bottom of the window on a short page and after the content on a long one. The classic layout is a column flexbox on the body (or a wrapper) with a minimum height of one window and the main region set to flex: 1:

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
}
main { flex: 1; }

With 100vh, a short page on the illustrative phone is 844 px tall and the footer starts below the 740 px window while the toolbars are showing, so the reader has to scroll to see it, and scrolling is what retracts the toolbars. With 100svh, the footer sits at the bottom of the visible window on load. If the reader does scroll and the toolbars retract, the window grows by 104 px and the page may end up showing a strip below the footer, which matches the body background and is normally invisible. With 100dvh, the footer travels down the screen during the scroll. svh is again the calm choice.

The second is a bar fixed to the bottom of the window, such as a cookie notice, an app-style tab bar or a "buy" bar. That needs no viewport unit at all. position: fixed with bottom: 0 places it against the bottom of the visible window, and padding-bottom: env(safe-area-inset-bottom) keeps its contents clear of a home indicator on devices that have one. env() and the safe-area-inset variables are supported from Chrome 69, Firefox 65 and Safari 11 in the compat data. If you see someone set a fixed bar's top to calc(100vh - 60px), that is the 100vh bug again: on the illustrative phone the bar lands 104 px below the visible window while the toolbars are showing.

The third use of the word, position: sticky on an element inside a scrolling container, has nothing to do with viewport units, and the same fixed-bottom rule applies.

The On-Screen Keyboard Is a Different Problem

A form at the bottom of a full-height panel is the other half of the "100vh mobile problem", and the new units do not fix it by default. The CSS spec notes that on-screen keyboards typically overlay content without shifting layout, and web.dev says the virtual keyboard "is not considered part of the UA UI." When the keyboard opens, svh, lvh and dvh all keep their values.

What changes instead is the visual viewport, the part of the page the reader can actually see. Chrome's developer blog describes the Chrome 108 change on Android: "Chrome on Android will no longer resize the Layout Viewport, and instead resize only the Visual Viewport." The aim, the post says, was to match Safari and Chrome on iOS.

To keep the illustrative numbers going: if a keyboard takes 300 px with the toolbars showing, the reader can see 440 px of page. A 100dvh chat panel is still 740 px tall, so its bottom 300 px, usually including the message input, is under the keyboard. A fixed panel's footer does not move up on its own.

The opt-in is the interactive-widget key in the viewport meta tag:

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

Chrome's post lists three values. resizes-visual is the default and resizes only the visual viewport, and the computed values of viewport units remain the same. resizes-content resizes both the visual and the layout viewport, and viewport units shrink. overlays-content resizes neither, and the keyboard sits on top. With resizes-content, the illustrative 100dvh chat panel becomes about 440 px tall when the keyboard opens and its input stays visible.

Support for interactive-widget in browser-compat-data 8.1.9 (published 12 November 2026): Chrome for Android 108, Samsung Internet 21.0, Firefox for Android 133, and Safari on iOS 27.3, a version the same data marks as a beta release, so Safari users may not have it yet. Desktop Chrome, Edge and Firefox are listed as not supporting it, which does not matter much since desktop keyboards are physical. A browser that does not recognise the key ignores it, so adding it is safe.

resizes-content is a page-wide decision. It makes every viewport unit on the page shrink when the keyboard opens, including the 100svh hero above the form, which will collapse to the space left over. If only one panel needs to react, the alternative is script: the VisualViewport API exposes the visual viewport's size to script, and it is available from Chrome 61, Firefox 91 (68 on Android) and Safari 13 in the compat data. There is also a CSS env(keyboard-inset-height) variable, but the compat data lists it for Chromium browsers only (Chrome 94), so it is not a cross-browser answer in 2026.

Typography: Width Units Inside clamp(), Never Height

Viewport units in font sizes are where this topic crosses into accessibility. WCAG 2.2 success criterion 1.4.4 requires that text can be resized up to 200 percent without loss of content or functionality, and the W3C's Understanding document lists a named failure, F94, "Failure of Success Criterion 1.4.4 due to incorrect use of viewport units to resize text." A font size in viewport units alone does not respond to the reader's text size setting.

The pillar guide covers the clamp() pattern: a rem floor, a rem ceiling, and a viewport-based middle term. Two points are specific to the viewport-relative units.

First, use width-based or inline-axis units (vw or vi) for the middle term, never height-based ones. A heading in dvh changes size while the reader scrolls, because the dynamic height changes. A heading in vh or svh changes size when the phone rotates in a way that has nothing to do with how much room the line has: on the illustrative phone, 6vh is 50.6 px in portrait, and in landscape the height becomes the short side, so the heading shrinks even though the line got longer. Line length is a width problem.

Second, the arithmetic of the floor. Take this rule:

h1 { font-size: clamp(2rem, 1rem + 4vi, 3.5rem); }

At the default 16 px root size, on the 390 px phone the middle term is 16 + 15.6 = 31.6 px, below the 32 px floor, so the heading is 32 px. On a 1,280 px wide window it would be 16 + 51.2 = 67.2 px, above the 56 px ceiling, so it is 56 px. The viewport term only decides where between the two rem bounds the heading lands. If the reader doubles their default text size to 32 px, the floor becomes 64 px and the ceiling 112 px, so the heading responds to their setting. Our typography scale guide shows how to pick the two bounds from a scale rather than by eye.

vi rather than vw is worth the habit even on a horizontal page. vi is the inline axis, so in a vertical writing mode it measures the direction text runs, which is what a fluid type size is trying to track.

The Horizontal Twin: 100vw and the Scrollbar

The height units get the attention, but width has its own classic bug. The spec says that, apart from one case, viewport units are "sized assuming that scrollbars do not exist." On a desktop browser with classic scrollbars, 100vw is the full window width including the scrollbar. An element set to width: 100vw is therefore wider than the space beside the scrollbar, and the page gains a horizontal scrollbar.

Illustrative numbers again: a 1,280 px window with a 15 px vertical scrollbar has 1,265 px of layout width. A 100vw banner is 1,280 px, 15 px too wide. On phones with overlay scrollbars the two numbers match, which is why the bug is often found late, on a desktop.

The exception in the spec: if the overflow or scrollbar-gutter value on the root element would unconditionally cause scrollbars or reserve space for them (for example html { overflow-y: scroll } or html { scrollbar-gutter: stable }), the computed viewport units in that axis are reduced to match. That is the spec's rule; we have not tested which browsers implement the reduction, so do not rely on it without checking in your target browsers. The dependable fix is to avoid 100vw for full-bleed elements: width: 100% on a block that is already full width, or a grid layout where full-bleed rows span all columns. The same spec note warns that overflow on the body can affect whether the root has scrollbars, but does not change the size of the viewport units.

A related use of vw that is not a CSS length at all is the sizes attribute on responsive images, where "100vw" tells the browser how wide the image slot is. That is covered in our srcset and sizes guide.

vi and vb: The Logical Pair

The i and b suffixes measure along the element's inline and block axes instead of fixed horizontal and vertical ones. In a horizontal writing mode such as English, inline is horizontal and block is vertical, so vi equals vw and vb equals vh (and svb equals svh, dvb equals dvh, and so on). In a vertical writing mode, used for some Japanese, Chinese and Mongolian layouts, they swap.

The spec adds a detail for cases where no element is being styled, such as media queries: vi and vb then use the initial value of writing-mode to choose their axis, which is horizontal.

So a full-height hero written with logical properties is min-block-size: 100svb, and it keeps meaning "one small viewport along the direction blocks stack" if the page or a component switches writing mode. If your site is horizontal only, the physical and logical forms give identical results, and the choice is about consistency with the rest of your stylesheet. The vi, vb and all the sv, lv and dv units shipped in the same browser versions, so the logical forms do not cost extra support.

Browser Support, Version by Version

These are the first versions with support listed in MDN's browser-compat-data, version 8.1.9, published 12 November 2026 (read from the published npm package on 13 November 2026). None of the entries is flagged as partial, prefixed or experimental.

FeatureChromeEdgeFirefoxSafariChrome AndroidFirefox AndroidSafari iOSSamsung Internet
vh, vw2012196251961.5
vi, vb10810810115.410810115.421.0
sv* units (svh, svw, svi, svb, svmin, svmax)10810810115.410810115.421.0
lv* units10810810115.410810115.421.0
dv* units10810810115.410810115.421.0
interactive-widget (viewport meta)NoNoNo27.310813327.321.0

Two observations from the table. The three families always arrive together, so there is no browser that supports svh but not dvh. And the keyboard opt-in is much newer than the units, so treat it as an enhancement.

The compat data also carries one old note: from Firefox 21, viewport-percentage lengths are invalid inside @page rules, which matters only for print stylesheets.

Fallbacks That Still Earn Their Place

Most sites can now write svh and dvh with a vh line above as a fallback, and nothing else. Two older techniques still appear in codebases, and it helps to know what they did.

The --vh custom property script. Before the new units, a common fix read the window's inner height in JavaScript, divided by 100, stored it in a custom property, and used calc(var(--vh) * 100) in CSS, updating on every resize event. It behaves like a hand-built dvh, with the same layout shifts during scroll, plus a flash of the wrong height before the script runs and a dependency on the script running at all. Once your supported browsers all appear in the table above, it can be replaced with a vh plus dvh pair, or better, a vh plus svh pair for in-flow sections.

Measuring with getBoundingClientRect. Script that positions things by measuring the window (for example, a tooltip that flips when it would run off the bottom) still needs real numbers. That is a job for the VisualViewport API, which describes the visual viewport (the part the reader can see) rather than the layout viewport.

If you use a build tool that adds fallbacks automatically, check its output for the two-line pattern rather than assuming. A missing vh line only matters for very old browsers, but a tool that rewrites svh to vh would bring the bug back for everyone.

A Decision Rule for Each Job

The pattern behind every row: in-flow content gets a stable unit, out-of-flow layers can follow the window, and decoration can be larger than the window.

JobUseWhyAvoid
Full-height hero, splash, intro sectionmin-height: 100svh (after a 100vh fallback)Fits with toolbars showing, never resizes during scroll100vh (overflows by the toolbar height), 100dvh (moves the page during scroll)
Stacked full-screen sections, scroll-snap slidesmin-height: 100svhEach dvh section would grow by the toolbar heightdvh
Fixed full-screen menu, drawer, lightboxheight: 100dvhOut of flow, so resizing moves nothing else; always matches the windowvh (clipped bottom when toolbars show)
Centred modalmax-height: 90dvh, scrolling middleUses the available room in both toolbar states90vh (taller than the window with toolbars showing)
App shell: map, chat, editorheight: 100dvh, plus interactive-widget=resizes-content if the keyboard mattersThe layout should equal the visible windowsvh (gap when toolbars hide), vh
Short-page footer at the bottombody min-height: 100svh with flex columnFooter visible on load, does not travel during scroll100vh
Fixed bottom barposition: fixed; bottom: 0; env(safe-area-inset-bottom)No viewport unit neededcalc(100vh - X) for top
Decorative fixed backgroundheight: 100lvhCovers the largest window, so no gap ever showssvh (gap), dvh (jumps)
Heading font sizeclamp(rem, rem + vi, rem)Tracks line length, respects text size settingsAny h or dvh unit; any viewport unit alone (WCAG F94)
Full-bleed banner widthwidth: 100% in a full-width parentExcludes the classic scrollbar100vw on desktop

When a case is not in the table, ask two questions. Is the element in the normal flow, so that a change in its size moves other content? Then use a stable unit, usually svh. Is it supposed to equal the visible window at every moment, and is it out of the flow? Then use dvh.

Checking It on a Phone

Desktop responsive-design modes resize the window to a phone's dimensions, but you should not assume they reproduce toolbars that slide away during scroll. The check that settles a unit choice is on a real device, and it takes a few minutes per page.

  1. Load the page fresh, without scrolling. Is the hero's call to action fully visible? Is the bottom edge of any modal or menu visible when you open it now?
  2. Scroll down a little, enough for the toolbars to retract, then scroll back to the top. Did anything below the hero move while your finger was on the screen? Did a strip of bare background appear behind a fixed layer?
  3. Open every form field near the bottom of a full-height panel. Is the field and its submit button visible above the keyboard?
  4. Rotate to landscape and repeat step 1. The height becomes the short side, and anything in svh or dvh gets much shorter, so check that min-height lets content grow rather than clip.
  5. Raise the browser's text size or zoom to 200 percent and repeat step 1, to catch fixed heights and viewport-only font sizes.

If you want numbers rather than impressions, a remote DevTools session to the phone lets you read an element's computed height and compare it with the window in each toolbar state. That gives you your own versions of the illustrative 740 and 844 above.

Viewport Unit Questions

Is dvh better than vh?

For the job vh was used for most often, a full-height section in the page, svh is better than both: it fits with the toolbars showing and stays still during scroll. dvh is better than vh for fixed overlays and app shells that must equal the visible window at every moment.

What is the difference between svh and dvh?

svh is 1 percent of the window height with the browser's toolbars showing, and it never changes while you scroll. dvh is 1 percent of the window height right now, so it is the same as svh with toolbars showing and grows to the large size when they retract.

Why is 100vh taller than the screen on mobile?

Because vh is now defined as the large viewport unit, sized as if the browser's toolbars are hidden. On first load the toolbars are usually showing, so the element is taller than the visible window by the height of those toolbars.

Does dvh change when the keyboard opens?

Not by default. The keyboard is not treated as browser UI, so svh, lvh and dvh keep their values. Adding interactive-widget=resizes-content to the viewport meta tag makes viewport units shrink when the keyboard opens, in browsers that support it.

Do I still need a vh fallback?

Only for browsers older than Chrome 108, Firefox 101 and Safari 15.4. Writing min-height: 100vh on the line before min-height: 100svh costs one line and does no harm, so most teams keep it.

Are svh, lvh and dvh different on desktop?

On a desktop browser without toolbars that retract during scroll, the small and large viewports are the same size by definition, so the three units resolve to the same value. They only differ where the browser has dynamic UI.

Should font sizes use dvh?

No. A dvh font size changes while the reader scrolls, and a font size in any viewport unit alone ignores the reader's text size setting, which W3C lists as WCAG failure F94. Use a width or inline unit inside clamp() with rem bounds.

From Here: The Rest of the Unit System

Viewport units are one row of the larger unit decision. The px vs rem vs em guide covers the other rows, including the root-relative units your clamp() floors and ceilings are written in, container query units for components, and the 200 percent text test that catches most unit mistakes before a reader does.

Sources

  • W3C, "CSS Values and Units Module Level 4" (Working Draft, 12 March 2024), https://www.w3.org/TR/css-values-4/: large, small and dynamic viewport sizes and units; default units mapped to large units for web compatibility; on-screen keyboards typically overlay content; vw, vh, vi, vb, vmin and vmax definitions; scrollbar rule and the overflow and scrollbar-gutter exception; the 8vw by 200mm example. Checked 13 November 2026.
  • MDN Web Docs, "length" (last modified 8 July 2026), https://developer.mozilla.org/en-US/docs/Web/CSS/length: small, large, dynamic and default viewport descriptions; "vh is equivalent to lvh"; dynamic units resizing during scroll. Checked 13 November 2026.
  • MDN browser-compat-data 8.1.9 (published 12 November 2026), npm package @mdn/browser-compat-data, https://github.com/mdn/browser-compat-data: css.types.length (vh, vw, vi, vb, viewport_percentage_units_small, _large and _dynamic), html.elements.meta.name.viewport.interactive-widget, api.VisualViewport, css.types.env (safe-area-inset and keyboard-inset variables), css.at-rules.supports. Checked 13 November 2026.
  • web.dev, "The large, small, and dynamic viewports" by Bramus (last updated 29 November 2022), https://web.dev/blog/viewport-units: 100vh bleeding out of the viewport, the three viewports, virtual keyboard not part of UA UI, dynamic values not updated at 60fps and throttled or debounced. Checked 13 November 2026.
  • Chrome for Developers, "Prepare for viewport resize behavior changes coming to Chrome on Android" by Bramus (last updated 28 October 2022), https://developer.chrome.com/blog/viewport-resize-behavior: Chrome 108 resizing only the visual viewport for the keyboard; interactive-widget values resizes-visual, resizes-content and overlays-content and their effect on viewport units. Checked 13 November 2026.
  • W3C WAI, "Understanding Success Criterion 1.4.4: Resize Text" (WCAG 2.2), https://www.w3.org/WAI/WCAG22/Understanding/resize-text.html: 200 percent resize requirement; failure F94 for viewport units used to resize text. Checked 13 November 2026.

The 390 by 844 and 390 by 740 pixel viewport sizes, the 300 px keyboard, the 1,280 px window with a 15 px scrollbar, and every pixel figure derived from them are illustrative inputs chosen by Lucky Graphics Editorial, not measurements of any device or browser. The arithmetic was checked in this run.