177

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"?

rdoyle720
  • 2,940
  • 3
  • 17
  • 19
  • avoid overflow hidden on html and body it is not a good solution if you want to use position sticky on any of its children elements… max-width seems to be a good way!!! – NeueDeutsche Aug 07 '20 at 14:49

9 Answers9

248

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

Mr_Green
  • 40,727
  • 45
  • 159
  • 271
  • 4
    Thanks, this works well to fix the issue, but I still think it's a little unintuitive default behavior. – phocks Oct 07 '14 at 07:25
  • @phocks IMO yes it seems unintuitive. BTW, I can't explain you well on this matter as I am not much expertise about this. – Mr_Green Oct 07 '14 at 07:32
  • 5
    About being unintuitive: according to caniuse.com this is a browserbug. http://caniuse.com/#feat=viewport-units --> Known issue 8: Currently all browsers but Firefox incorrectly consider 100vw to be the entire page width, including vertical scroll bar, which can cause a horizontal scroll bar when overflow: auto is set. – Jacob van Lingen Aug 05 '15 at 09:26
  • 90
    If `max-width: 100%` is the width of the viewport without scrollbars, then you didn't need `100vw` in the first place :-) You could just have use `width: 100%` because the element doesn't have any positioned ancestor, so its reference is the body. – Capsule Apr 20 '16 at 23:14
  • @Capsule That is (no longer?) correct. I quote: “**However, any scrollbars are assumed not to exist.**” from https://drafts.csswg.org/css-values-3/#viewport-relative-lengths in version “Editor’s Draft, 20 May 2018” – Kissaki Jun 02 '18 at 13:58
  • I’m not sure what the reasoning for that is though. I agree that this is unintuitive. Maybe this is a simplifaction for implementation (so changes in scrollbar display do not change the viewport size), or some thought about a use case with the scrollbars hidden and potentially reimplemented. Given that width 100% works fine though, it’s unfortunate the 100vw does not work the same. – Kissaki Jun 02 '18 at 14:00
  • MDN actually [says](https://developer.mozilla.org/en-US/docs/Web/CSS/length#Viewport-percentage_lengths) that this is only for overflow auto. If overflow is set to scroll the (always visible) scrollbars are subtracted. … That makes it even less intuitive… – Kissaki Jun 02 '18 at 14:03
  • 1
    @Kissaki my comment is still correct. The original question was about having an element that covers 100% of the available width. You still don't need the vw unit to achieve that if your element is a direct child of body. Substracting the scrollbars when they are forced to be visible kinda make sense as the viewport is then ALWAYS wihtout the scrollbar width available, but yeah, not ideal. – Capsule Jun 05 '18 at 04:45
  • Note that this is only an issue on windows. On Mac or Android the scrollbars are placed on top of the content and disappear once you're done scrolling so they don't affect the view width. – Adam Reis Aug 22 '18 at 11:27
  • 38
    This doesn't solve anything! max-width only works because the element is a direct decendant of the body! In any real-world case where you would use 100vw instead of 100%, (Such as an element inside a container), this won't work. – Eliezer Berlin Apr 16 '19 at 08:12
  • @EliezerBerlin I agree with you.. Anyway, this worked for OP's case. – Mr_Green Apr 16 '19 at 14:50
  • 3
    I can't use width 100% because my div is in a container that I don't know the width or padding of. That's the whole reason to use 100vw instead of 100%, so this answer is pointless. And it happens on Mac also if your setting is to always show scrollbars, even though there is no scrollbar. – Curtis Jul 03 '19 at 23:42
  • 1
    I love CSS, I love CSS, I love CSS... – fullStackChris Dec 08 '21 at 20:25
  • this is still helps me thank you – Sithum Dilshan Dec 12 '21 at 12:30
  • @Mr_Green Does this solution works for max-height:100% as well? (with the height: 100vh equivalent)?. – Kosem Jan 03 '22 at 15:33
67

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/

wf4
  • 3,727
  • 2
  • 34
  • 45
  • 4
    Doing this causes content to appear below the scrollbar. http://jsfiddle.net/NBzVV/1/ For this to be a suitable workaround you'd need to add right padding. – James Donnelly Apr 29 '14 at 14:31
  • 1
    Yep, well spotted. Adding `max-width:100%` to `.box` will prevent that. – wf4 Apr 29 '14 at 14:35
  • 8
    "so the horizontal scroll will be added to allow you to see under the vertical scroll" <- this sentence helped my brain make visual sense of what was really going on. +1 – Ivan Durst Sep 16 '15 at 01:45
  • 2
    Just a note about `overflow` even if you add it to the `x` none of the `postition: sticky` stuff will work. – T.Chmelevskij Dec 20 '19 at 10:30
36

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.

  • 2
    Love this. quite elegant – andrevenancio May 20 '20 at 23:42
  • This is perfect because it is then available globally. Thank you. – fvaldez421 Jun 08 '20 at 23:10
  • This is such a great technique, thank you for sharing! One gotcha is that this script needs to run after the dom is loaded for the initial sizing, so either put it in the footer, or add a DOMContentLoaded event. – dug Dec 10 '20 at 19:34
  • Excellent technique! To simplify the CSS you can add the following code to your stylesheet: html{ --vw:1vw }; This allows you to use var(--vw) without a fallback, as the value of --vw defined in CSS will be overridden by JS. If JS fails, the value defined in CSS works as a fallback. – brett Aug 09 '21 at 07:28
  • this is amazing – pacman Feb 08 '22 at 09:11
  • Worked beautifully for me. Thanks! – cotton Apr 24 '23 at 14:32
  • 1
    Doesn't this assume the page will start with a scrollbar? What happens when content addition overflows the page only after the fact? – Drazen Bjelovuk May 03 '23 at 18:47
3

If you're working in a framework (ASP.NET for example) where there's possibly a parent element wrapping around the html, then setting the html's max-width to 100% will solve the problem without using the "band-aid" solution overflow-x: hidden.

html {
   max-width: 100%;
}

The reason why 100vw is causing a horizontal scrollbar is well explained in other responses: 100vw counts the width of the vertical scrollbar to the html itself. I think this is a little absurd, but it is what it is, you know :)

Orlyyn
  • 2,296
  • 2
  • 20
  • 32
1

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.

Cornflex
  • 639
  • 5
  • 15
  • Uhm, did the accepted answer change? You’re suggesting the same thing as the accepted answer. This is why answers should be complete by themselves. – Kissaki Jun 02 '18 at 14:05
  • The accepted answer proposes adding `max-width: 100%`. I proposed changing `width: 100vw` to `width: 100%`. I updated my answer to be self-contained. – Cornflex Jun 03 '18 at 11:20
  • 2
    There are other browsers besides Chrome, and some deal with the scrollbar differently. – LocalPCGuy Aug 30 '19 at 13:48
1

to get rid of the scrollbar width included in vw i had to do this:

html, body {
    overflow-x: hidden;
    height: 100vh;
}
manuel-84
  • 2,582
  • 1
  • 23
  • 23
  • 1
    Awesome, the other solutions didn't solve the problem for me but this did it. (Changing the width to 100% did reduce the width of the objects, since they weren't stretched to the complete width of the view anymore). – subjord Jan 11 '21 at 20:30
  • 6
    This will have other side-effects, like breaking `position: sticky` completely. – wintercounter Mar 23 '21 at 15:53
0

Being inspired by Stepan Shatkovski's method, I concluded this does not work in all cases. So I modified it a bit to work properly with element resizing and also renamed it sightly to avoid confusion:

function vws() {
  let vws = document.documentElement.clientWidth / 100;
  document.documentElement.style.setProperty('--vws', `${vws}px`);
}
vws();
let ro_vws = new ResizeObserver(() => { vws(); });
ro_vws.observe(document.body); // add elements with potential scroll bar
Christian
  • 11
  • 2
-1
*,
html,
body {
  margin: 0;
  padding: 0;
  overflow: hidden;/*add This*/ 
}
/*and enjoy ^_^ */
  • 16
    Hiding a problem does not solve it. While your approach does indeed remove the overflow, it simply hides it. This can cause problems when content should be displayed outside (because of whatever reason) – Daniel Steiner Mar 29 '20 at 23:29
  • 4
    Hey user13149444! Code-only answers may solve the problem but they are much more useful if you explain how they solve it. Community requires theory as well as code both to understand your answer fully. – RBT Mar 30 '20 at 00:59
-4

You can try:

*{ box-sizing: border-box}

the reason why the content is flowing out of screen is maybe you have extra padding or border on the div and it cause the content out of the broswer

qlian1000
  • 15
  • 1