Viewport units: vw, vh, vmin, vmax

The viewport is the area where the browser renders the site. This is your screen minus the reserved space of the browser chrome. Sometimes you want to size an element based on that viewport, like a sidebar. This can be done using a unit we’re all familiar with: percentages.


.sidebar { width: 25% }

Let’s set the height equal to the viewport.


html, body { height: 100%; }
    
.sidebar {
  height: 100%;
  width: 100%;
}

What’s going wrong here? Why does html and body require a height? Percentages are relative to it’s parent properties. When the parent’s height is defined by it’s children, there’s no known height to set, so the height is ignored entirely. That means you would have to set the height on every parent element in the DOM tree. You could also use the new viewport units.


Viewport-percentage lengths

The viewport units are a new set of units designed for the challenges we face today. One-pagers, full-width grids, typography, and many other things rely on the size of the viewport. Previously, we hacked these challenges using percentages as mentioned earlier, or JavaScript.

This new set of units consists of four different units. Two for each axis, and a minimum and maximum value of the two.

  • vw: 1/100th viewport width
  • vh: 1/100th viewport height
  • vmin: 1/100th of the smallest side
  • vmax: 1/100th of the largest side

Note: IE9 uses vm instead of vmin. It does not support vmax.

Just to clarify: 1vmax equals 1vh in portrait mode, whilst in landscape mode, 1vmax will equal 1vw.


Caution: one major drawback

Imagine you’re building a full-width square grid using these units. I suppose that would look something like this:


.grid {}
    
.grid::before,
.grid::after {
  clear: both;
  content: '';
  display: block;
}
    
.grid__item {
  box-sizing: border-box;
  float: left;
  height: 50vw;
  padding: 2em;
  width: 50vw;
}

See the Pen Viewport units by Tim Severien (@timseverien) on CodePen.

At some point, the items will overflow the viewport. On Windows, a scroll bar will appear, slightly shrinking the viewport. On OS X, a smart scroll bar will appear over the content which shows and hides automatically, thus not affecting the viewport. How is that relevant? Here’s a bit of the specification:

“When the value of ‘overflow’ on the root element is ‘auto’, any scroll bars are assumed not to exist.”
http://www.w3.org/TR/css3-values/#viewport-relative-lengths

That means, when the root element’s overflow is set to auto, which is the default value, scroll bars are assumed not to exist. That means 100vw is the width of the viewport, scroll bar included. In OS X, everything will look fine. On Windows however, the two grid items together are wider than the viewport, scroll bar excluded, thus will be unable to render the two blocks next to each other.

Luckily, this is isn’t a difficult problem to overcome. The easiest way is to simply set the parent’s overflow property to hidden if the parent should grow along with the content. If it should scroll, set it to scroll.

If you’re using the latter but you’re annoyed a scroll bar is displayed even when you cannot scroll, you can use JavaScript to compare the element’s height to the amount of scrolling you can do.


var element = document.documentElement;
  
if(element.scrollHeight > element.clientHeight) {
  // Overflow detected; force scroll bar
  element.style.overflow = 'scrollbar';
} else {
  // No overflow detected; prevent scroll bar
  element.style.overflow = 'hidden';
}

For more robust implementations to detect whether a scroll bar is visible or not, see “Crossbrowser JavaScript Scrollbar Detection” by Tyler Cipriani or “Detect If a Page Has a Vertical Scrollbar” on Stack Overflow if you prefer jQuery.

Real-world usage

A very common use for these units is typography. With the viewport units, you can easily put text over the entire width or height of the screen, like so:

vw example:

See the Pen Viewport units by Tim Severien (@timseverien) on CodePen.

vh example:

See the Pen Viewport units by Tim Severien (@timseverien) on CodePen.


Hopefully the above has given you an insight into the wonderful world of viewport units.

24 thoughts on “Viewport units: vw, vh, vmin, vmax”

  1. Howdy!
    super great article – honestly this is the first time I read about these units. I was reading this with a futurama fry face “reaaalyyyy?”,
    Well anyway. About the whole scrollbar situation: Is there a good way around this? I mean would I have to detect a windows platform and set the parent container to scroll; ? Or am I confused now?
    Thanks a lot for writing this down anyway!
    n

    • Thank you! Yeah, the property is ready for production in my opinion. If the used unit is not supported, you can easily provide that classic CSS fallback we use for calc() too, like so:

      font-size: 5em;
      /* If vw is supported, font-size is overwritten. If not, UA will use 5em */
      font-size: 20vw;

  2. Yesterday I was thinking that there should be a way for sizing the text relative to the window to avoid too much mediaqueries for some elements’ font-size, and today I found this article not knowing those units even exits… amazing. Thank you! (and thanks to responsive design weekly also).

  3. Hello.

    I’m very interested in web design and started building my own web site.
    I tried to use viewport height to get a nice landing screen and footer when someone visits the mobile version of my site. However the nav bar on mobile is not added in the viewport size calculation.
    This causes extremely annoying jumps in the document because the document is constantly getting resized. (You scroll down nav bar dissapears, document jumps, scroll up, nav bar appears, document jumps, …)

    Any solutions to this?

    • Excellent question!

      I’ve come across this problem as well! Unfortunately, the disappearing of the chrome when scrolling on mobile browsers triggers a resize. Therefor, the document does indeed jump when scrolling, as would it when using percentages to set a height.

      As with the scroll bar mentioned in this article, there is no graceful solution to the problem. In 2013, Paul Kinlan wrote a great article “Building an amazing fullscreen mobile experience” in which he describers several tactics to get rid of the address bar. The Fullscreen API he mentions is one option — but isn’t great. Another method he mentions is using window.scrollTo(0, 1). This allows you to remove the address bar on load. But when a user scrolls back up, it simply reappears and we’re back at start.

      At the end of the day, none of the solutions are graceful and you should either accept that there could be some jumping on mobile browsers or use an alternative method, like using JavaScript.

      You could detect the screen ratio and set a vw instead. When the address bar disappears, the width of the screen remains the same, so no jumping! When resizing the browser, you’ll have to redo it though. Look at the code.

      • Thanks for a great comment!

        Maybe i should have mentioned I know some beginner Javascript/Jquery. I’m currently studying to become a webdev/webdesigner.
        I managed to somewhat solve the issue. The main annoying thing on the mobile auto resizing was the jump in the page.
        Let’s say you’re in the middle of your document and your url bar goes away. A viewport resize triggers and every element with ‘vh’ will get longer. Your document becomes longer, but more importantly the stuff that got longer in the first half is what makes your browser jump. The elements that you haven’t seen yet in the second half also get longer but they don’t affect your current position (our jumpy behavior).

        So in my current project I’m using some Jquery to make the header (full screen landing page) to only load once using a simple bool and then headerHeight = $(window).height();
        I tried to minimize the use of vh in my whole document except for the elements at the bottom. A footer and form 100vh combined.

        I now have a way nicer experience on my android phone than in the beginning. Maybe you already know all this but I thought I’d write it down for other people who got stuck on this like me.

        TL;DR.
        The higher you are in your document the more you should avoid ‘vh’ or use jquery to set the height only once.
        When you’re lower in your document it becomes less noticable and more acceptable to use vh.

    • Thanks guys for this interesting discussion, it was very helpful using Your method to set the full-screen element’s height to the window height using jQuery, And managed to fix the in-consistency between mobile browsers. The only problem appears on desktop on a resizable window; This value doesn’t change automatically, I think I can use jQuery’s setinterval() to check the window ‘s height each 1 second or something and readjust the wanted element height accordingly. any way thank you.

  4. thank you so much, that scroll bar problem was driving me crazy, everything looked strange on my old computer and fine on the new retina..overflow: hidden for the hmtl frame and all looking nice now! thanks!!!

  5. Think there’s a typo in the last vh example css.

    Font-size is 10% of the viewport height. (it should say 20% here)

  6. When using this with text, is there a way to limit the maximum or minimum size regardless of the size of the screen (viewport)?

Comments are closed.