A Look at CSS Viewport Units

Viewport units were introduced with the CSS Values and Units level 3 spec. They allow to size elements and font sizes as a percentage of the total width or height of the user’s screen (the viewport).

Let’s explore what we can accomplish design-wise by making use of these units in our CSS.

vh & vw

vh stands for viewport height and vw is for viewport width. Hence, setting an element to a width value of 50vw means that the element will have a width that’s 50% of the viewport size, and this stays true when the viewport is resized.

Screen mockup demonstrating viewport unit placement

Percentage vs Viewport Units

Since viewport units are a percentage of the size of the viewport, it can seem at first glance that specifying sizes as percentage values would be equivalent. The difference is that viewport units are always a percentage of the total size of the viewport, while a percentage value applied on an element is a percentage of the element’s parent, not necessarily the whole viewport.

vmin & vmax

vmin and vmax might seem a little trickier to understand, but it’s all really simple in the end. With vmin, we size as a percentage of the smallest between the width or the height of the viewport, and with vmax, we size as a percentage of the largest between the two.

Say, for example, that our viewport is 1440px wide and 800px tall, if we set element to have a width of 50vmin, it’ll be 50% of the height (400px), and if instead we set the element to have a width of 50vmax, it’ll be 50% of the width (720px). If the viewport was instead 800px width and 1440px tall, we’d get the exact opposite result.

vmin and vmax can be useful to size title font sizes as we’ll illustrate below.

Viewport Units for Hero Sections

Viewport units are great to help create hero sections that take up the exact height of the viewport.

Let’s create an example to illustrate. Say we want to create 2 sections that both take up the full width of the viewport and that together take up the full height of the viewport. First, some simple markup for our sections:

<section class="hero">
  <h1>I'm a Hero Title</h1>
</section>
<section class="sub-hero">
  <h1>I'm the Subhero</h1>
</section>

And then our styles:

.hero {
  height: 75vh;
  background: linear-gradient(45deg, #DA4453, #89216B);
}

.sub-hero {
  height: 25vh;
  background: linear-gradient(115deg, #4e54c8, #8f94fb);
}

.hero, .sub-hero {
  display: flex;
  align-items: center;
  justify-content: center;

  width: 100vw;
  position: relative;
  left: 50%;
  margin-left: -50vw;
}

Now, pulling off the two sections together taking up the full height is easy: 75vh for the hero section and 25vh for the sub-hero section. But articles on this site are inside a container with a max-width value of 55rem, so it gets trickier here for our sections to break out of the container. Applying a width of 100vw alone doesn’t do the trick because the elements still start on the left edge of the parent container.

Thanks to a trick demonstrated in this pen by Sven Wolfermann, and explained in this CSS-Tricks article, we can make use of viewport units once again to effectively breakout of the container element and take up the full width of the viewport. It involves pushing the element to the center of the viewport and then pulling it back using a negative margin of -50vw.

Here's the result:

I'm a Hero Title

I'm the Subhero


Try resizing your browser window and notice how the sections always take up the exact width and height of the viewport

Hero section with a navbar

Say you want to design a hero section that takes up the fullwidth of the viewport and the full height, minus the height of your site’s navbar. If you know the height of the navbar, that’s easy to do using the calc() function. Say, for example, that our navbar has a height of 3rem:

.hero {
  height: calc(100vh - 3rem);
  width: 100vw;
}

Vertical scrollbar caveat

If your operating system is set to always show scrollbars, you may face a problem where 100vw doesn’t take into account the visible scrollbar and you end up with some horizontal scrolling because of 100vw being slightly wider than the viewport minus the scrollbar width. Answers to this Stack Overflow question give out a few possible solutions.

For the example in this post, I fixed the problem by adding overflow-x: hidden to the both the html and body elements:

html, body {
  overflow-x: hidden;
}

Thanks to Michael Coker for pointing out this problem!

Viewport Units for Titles

Viewport units are not only great for large elements like hero sections, but they can also be used to size elements like titles and have their font size adjust automatically as a function of the viewport size. This way, we can potentially avoid having to set multiple breakpoints with set font sizes, which can simplify our style rules.

Here for example we have a title width a font-size of 5vw:

h1 {
  font-size: 5vw;
  text-align: center;
}

I'm a Title at 5vw

It works and our title will be larger on large viewports and smaller on small viewports. One problem is that the title may become too large on very large viewports and too small on very small viewports. Because of that, we may still have to use breakpoints to define static font size values for viewports over or under a certain size.

Or, in this case, we can fix part of the problem by making use of the vmax unit to ensure that our title doesn’t become too little. Here our title will have a font size of 4% of the largest between the width or the height of the viewport:

h1 {
  font-size: 4vmax;
  text-align: center;
}

I'm a Title at 4vmax

Browser Support

Can I Use viewport-units? Data on support for the viewport-units feature across the major browsers from caniuse.com.

  Tweet It

🕵 Search Results

🔎 Searching...