100vw causing horizontal overflow, but only if more than one?

Say you have this:

html, body {margin: 0; padding: 0}
.box {width: 100vw; height: 100vh}

<div class="box">Screen 1</div>

You'll get something that fills the screen, no scrollbars. But add another:

<div class="box">Screen 1</div>
<div class="box">Screen 2</div>

You get not only vertical scrollbars (expected), but a slight horizontal scroll.

I realize you could omit the width, or set it to width: 100%, but I'm curious why this is happening. Isn't 100vw supposed to be "100% of the viewport width"?


Solution 1:

As already explained by wf4, the horizontal scroll is present because of the vertical scroll. which you can solve by giving max-width: 100%.

.box {
    width: 100vw;
    height: 100vh;
    max-width:100%;  /* added */
}

Working Fiddle

Solution 2:

scrollbars will be included in the vw so the horizontal scroll will be added to allow you to see under the vertical scroll.

When you only have 1 box, it is 100% wide x 100% tall. Once you add 2, its 100% wide x 200% tall, therefore triggering the vertical scrollbar. As the vertical scrollbar is triggered, that then triggers the horizontal scrollbar.

You could add overflow-x:hidden to body

html, body {margin: 0; padding: 0; overflow-x:hidden;}
.box {width: 100vw; height: 100vh; background-color:#ff0000}
.box2 {width: 100vw; height: 100vh; background-color:#ffff00}

http://jsfiddle.net/NBzVV/

Solution 3:

I had a similar problem and came up with the following solution using JS and CSS variables.

JS:

function setVw() {
  let vw = document.documentElement.clientWidth / 100;
  document.documentElement.style.setProperty('--vw', `${vw}px`);
}

setVw();
window.addEventListener('resize', setVw);

CSS:

width: calc(var(--vw, 1vw) * 100);

1vw is a fallback value.

Solution 4:

Update: As of Chrome version 66, I cannot reproduce the behaviour reported by question anymore. No workaround appears to be needed.


Original Answer

This is actually a bug as reported in this answer and the comments above.

While the workaround in the accepted answer (adding .box {max-width: 100%;}) generally works, I find it noteworthy that it does not currently work for display:table (tested in Chrome). In that case, the only workaround I found is to use width:100% instead.

  • Broken Fiddle with display:table
  • Working Fiddle with display:table and width:100%