If an element is set to width: 100vw;
and there is a vertical scrollbar the width of the element will be equal to the viewport plus the width of the scrollbar.<
Basically the answer is no, if you have a vertical scrollbar there is no way to make 100vw equal the width of the visible viewport. Here are the solutions that I have found for this issue.
warning: I have not tested these solutions for browser support
tl;dr
If you need an element to be 100% width of the visible viewport(viewport minus scrollbar) you will need to set it to 100% of the body. You can't do it with vw units if there is a vertical scrollbar.
1. Set all ancestor elements to position static
If you make sure that all of .box
's ancestors are set to position: static;
then set .box
to width: 100%;
so it will be 100% of the body's width. This is not always possible though. Sometimes you need one of the ancestors to be position: absolute;
or position: relative;
.
Example
2. Move the element outside of non-static ancestors
If you can't set the ancestor elements to position: static;
you will need to move .box
outside of them. This will allow you to set the element to 100% of the body width.
Example
3. Remove Vertical Scrollbar
If you don't need vertical scrolling you can just remove the vertical scrollbar by setting the <html>
element to overflow-y: hidden;
.
Example
4. Remove Horizontal Scrollbar This does not fix the problem, but may be suitable for some situations.
Setting the <html>
element to overflow-y: scroll; overflow-x: hidden;
will prevent the horizontal scrollbar from appearing, but the 100vw element will still overflow.
Example
Viewport-Percentage Lengths Spec
The viewport-percentage lengths are relative to the size of the initial containing block. When the height or width of the initial containing block is changed, they are scaled accordingly. However, when the value of overflow on the root element is auto, any scroll bars are assumed not to exist. Note that the initial containing block’s size is affected by the presence of scrollbars on the viewport.
It appears that there is a bug because vw units should only include the scrollbar width when overflow is set to auto on the root element. But I've tried setting the root element to overflow: scroll;
and it did not change.
Example
An element with width: 100vw
only causes horizontal scrollbars when one of it's parents has a horizontal padding. Otherwise it should fit in well.
Check this fiddle: http://jsfiddle.net/1jh1cybc/ The .parent2
has a padding, which causes the inner .box
to break out of it's parent width.
Edit:
In your case I guess your body
has a margin. Check this fiddle out with you code and try to remove the body css rule: http://jsfiddle.net/1jh1cybc/1/
Here's what I do:
div.screenwidth{
width:100%; /* fallback for browsers that don't understand vw or calc */
width: calc(100vw - 17px); /* -17 because vw is calculated without the scrollbar being considered & 17px is width of scrollbars */
position:relative; /* use this if the parent div isn't flush left */
right: calc((100vw - 17px - 100% )/2);
}
I was also struggling with this, and I also thought of CSS variables as the solution. CSS variables aren't supported in IE11 though so I tried something else:
I fixed it by calculating the width of the scroll bar: subtracting the width of the body
(not including scroll bar) from the width of the window
(including the scroll bar). I use this to add it to the 100% of the body, see plusScrollBar
variable.
JS:
// calculate width of scrollbar and add it as inline-style to the body
var checkScrollBars = function() {
var b = $('body');
var normalw = 0;
var scrollw = 0;
normalw = window.innerWidth;
scrollw = normalw - b.width();
var plusScrollBar = 'calc(' + '100% + ' + scrollw + 'px)'
document.querySelector('body').style.minWidth = plusScrollBar;
}();
CSS:
html{
overflow-x: hidden;
}
Why I like this: it takes in consideration that not all scrollbars are the same width or considered as conserved space at all. :)
I had the same problem. When I changed the vw units to percentage, horizontal scrollbar disappeared.