CSS Viewport Units: A Practical Guide
CSS viewport units (vw, vh, vmin, vmax) let you size elements relative to the browser window, making responsive design more intuitive. You enter no data—this is a reference guide—but you’ll learn exactly what each unit does, how to use them safely, and where they fall short.
What Are Viewport Units?
Viewport units are CSS length units that reference the size of the viewport—the visible area of the browser window, excluding browser chrome like toolbars and scrollbars. They were introduced in CSS3 and are now supported in all modern browsers. Unlike percentage widths, which are relative to the parent element, viewport units are always relative to the viewport itself.
There are four units:
- vw – 1% of the viewport width. So 50vw is half the width of the browser window.
- vh – 1% of the viewport height. 100vh equals the full visible height.
- vmin – 1% of the smaller of the two (width or height).
- vmax – 1% of the larger of the two.
For example, on a 1200×800 viewport, 1vw = 12px, 1vh = 8px, 1vmin = 8px, and 1vmax = 12px.
How They Compare to Percentages and rem
Percentages are relative to the parent element. If a parent is 600px wide, a child at 50% is 300px, regardless of viewport size. Viewport units, on the other hand, are absolute relative to the window. This makes them ideal for full-screen sections, hero images, and fluid typography.
rem units are relative to the root font size (usually 16px). They are great for consistent spacing and text scaling, but they don’t respond to the viewport. Viewport units respond to the window, which is why they’re often used for elements that should always fill the screen, like a landing page hero.
Choosing the Right Unit for Your Layout
Here’s a practical decision tree:
- Full-height sections: Use
min-height: 100vhfor a section that should fill the entire viewport height. - Full-width elements: Use
width: 100vwto force an element to span the entire viewport width, even if the parent has padding. - Responsive fonts: Use
font-size: calc(16px + 1vw)to make text scale smoothly with the viewport while maintaining a minimum size. - Square elements: Use
width: 50vmin; height: 50vminto always get a square that fits in the viewport. - Avoid vmax for most layouts because it can cause unexpected results on portrait/landscape switches.
For most text, rem is safer than vw because it respects user browser settings. If you use vw for fonts, always pair it with calc() to ensure a minimum size.
Common Pitfalls and Mobile Issues
The biggest issue with vh is on mobile browsers. On iOS Safari and older Android browsers, 100vh includes the area hidden behind the browser’s address bar. This causes elements to be taller than the visible viewport, leading to content being cut off or the need to scroll unnecessarily.
Solutions:
- Use
100dvh(dynamic viewport height) for mobile, which updates as the toolbar hides/shows. Supported in modern browsers. - Fallback: use
100vhfirst, then override with100dvhin a@supportsblock. - Alternatively, use
min-height: 100vhand let content expand if needed.
Another common mistake is using width: 100vw on an element that is inside a container with padding. The viewport width includes the scrollbar, so the element may overflow horizontally. Use width: 100% instead, or add overflow-x: hidden to the body.
Practical Examples
Here are three real-world uses:
- Hero section –
min-height: 100vh; display: flex; align-items: center; justify-content: center;creates a full-screen banner that centers content. - Fluid typography –
font-size: calc(16px + 0.5vw)gives a base of 16px and adds 0.5% of viewport width. At 1200px wide, the font is 22px; at 375px, it’s about 17.9px. - Sticky footer – Use
min-height: 100vhon the body wrapper, then push the footer down withmargin-top: autoon a flex column.
Accessibility and User Settings
One major concern: viewport units ignore user font-size settings. If a user has set their browser to 20px base font, 1vw still equals 1% of the viewport, not 1% of their preferred font size. This can make text too small for some users.
Best practice: use rem for body text, and reserve vw for decorative elements or headings where you also set a minimum size via calc() or clamp(). The clamp() function is perfect: font-size: clamp(16px, 2vw, 32px) ensures a minimum of 16px, a preferred 2vw, and a maximum of 32px.
Alternatives and Modern Options
Besides vw, vh, vmin, and vmax, CSS now offers:
- dvh, svh, lvh – dynamic, small, and large viewport heights.
svhis the smallest possible viewport (when toolbars are shown),lvhis the largest (when hidden), anddvhupdates dynamically. - vi and vb – inline and block viewport units, relative to the writing mode. Rarely used but useful for vertical text.
- Container queries – instead of viewport, you can size elements relative to their container using
cqwunits, which is more flexible for components.
For most projects, a combination of rem for spacing and typography, vh for full-page sections, and clamp() for fluid text is the most robust approach.
Frequently Asked Questions
Should I use 100vh for a full-screen background?
Yes, but be aware of mobile issues. Use min-height: 100vh and then add min-height: 100dvh for modern browsers to get the correct height on mobile. This ensures the background covers the visible area without causing scroll issues.
What’s the difference between vw and %?
% is relative to the parent element’s width (or height, depending on the property). vw is always relative to the viewport width. For example, a div with width: 50% inside a 800px parent is 400px, but width: 50vw is 50% of the browser window, regardless of parent.
Can I use viewport units for font-size?
Yes, but it’s risky for accessibility. Use clamp() to set minimum and maximum sizes. For example, font-size: clamp(16px, 2vw, 24px) ensures readability on all screens.
Why does 100vw cause horizontal scroll?
Because 100vw includes the scrollbar width (typically 15-20px). If the page has a vertical scrollbar, the element becomes wider than the visible viewport, causing horizontal overflow. Use width: 100% instead, or set overflow-x: hidden on the body.
Are viewport units supported in all browsers?
Yes, all four original units (vw, vh, vmin, vmax) are supported in all modern browsers, including IE9+. The newer dvh, svh, and lvh are supported in Chrome 108+, Firefox 101+, and Safari 15.4+, but not in older browsers. Always provide a fallback.
What’s the best way to center an element vertically?
Use min-height: 100vh on a flex container with align-items: center. This is more robust than using margin-top: 50vh because it accounts for content height and avoids scroll issues.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.