Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent 100vw from creating horizontal scroll

Tags:

css

scroll

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.

Is it possible to prevent this?

Is it possible to prevent this without disabling horizontal scrolling on the entire page? Aside from changing my css/markup to make the element 100% of the body width I can't think of anything.

Tested in Chrome Version 43.0.2357.81 m & FF 36.0.1 & Opera 20.0.1387.91 on Windows 8.1

Here is the code as requested:

Example

html

<div class="parent">     <div class="box"></div> </div> <div class="tall"></div> 

css

body { margin: 0; } html { box-sizing: border-box; } *, *::before, *::after {     box-sizing: inherit;     position: relative; } .parent {     background: rgba(0, 0, 0, .4);     height: 100px;     width: 5rem;     margin-bottom: 25px; }  .box {     position: absolute;     top: 0;     left: 0;     background: rgba(0, 0, 0, .4);     height: 50px;     width: 100vw; }  .tall {     height: 100rem; } 
like image 972
Hal Carleton Avatar asked May 27 '15 17:05

Hal Carleton


People also ask

Why is 100vw overflowing?

There, 100vw causes horizontal overflow, because the vertical scrollbar was already in play, taking up some of that space.

Does scrollIntoView work horizontally?

scrollIntoView(true);", element); This works for vertical scrolling but not for horizontal.

Does 100vw include scrollbar?

Many assume that width: 100vw is the same as width: 100% . This is true on a page that doesn't scroll vertically, but what you might not realize is that the viewport actually includes the scrollbars, too.

How do I enable horizontal scrolling in Visual Studio?

Enables horizontal scrolling by holding down the Shift key and spinning the mouse wheel in Visual Studio 2017, 2019 and 2022.


2 Answers

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

like image 84
Hal Carleton Avatar answered Sep 22 '22 17:09

Hal Carleton


This is a more full-fledged approach to the bug since it still exists in modern browsers. Setting overflow-x: hidden can cause problems or be undesirable in many situations.

A full example is available here: http://codepen.io/bassplayer7/pen/egZKpm

My approach was to determine the width of the scroll bar and use calc() to reduce the 100vw by the amount of the scroll bar. This is a little more complicated because in my case, I was pulling the width of the content out from a box that had a defined with so I needed to declare the margin as well.

A few notes regarding the code below: first, I noticed that 20px seems to be a rather broad magic number for the scroll bars. I use a SCSS variable (it doesn't have to be SCSS) and code outside of @supports as a fallback.

Also, this does not guarantee that there will never be scroll bars. Since it requires Javascript, users that don't have that enabled will see horizontal scroll bars. You could work around that by setting overflow-x: hidden and then adding a class to override it when Javascript runs.

Full SCSS Code:

$scroll-bar: 20px;  :root {     --scroll-bar: 8px; }  .screen-width {   width: 100vw;   margin: 0 calc(-50vw + 50%);      .has-scrollbar & {         width: calc(100vw - #{$scroll-bar});         margin: 0 calc(-50vw + 50% + #{$scroll-bar / 2});     }      @supports (color: var(--scroll-bar)) {         .has-scrollbar & {             width: calc(100vw - var(--scroll-bar));             margin: 0 calc(-50vw + 50% + (var(--scroll-bar) / 2));         }     } } 

Convert the above to plain CSS just by removing #{$scroll-bar} references and replacing with the px value

Then this Javascript will set the CSS Custom Property:

function handleWindow() {     var body = document.querySelector('body');      if (window.innerWidth > body.clientWidth + 5) {         body.classList.add('has-scrollbar');         body.setAttribute('style', '--scroll-bar: ' + (window.innerWidth - body.clientWidth) + 'px');     } else {         body.classList.remove('has-scrollbar');     } }  handleWindow(); 

As a side note, Mac users can test this by going to System Preferences -> General -> Show Scroll Bars = Always

like image 37
bassplayer7 Avatar answered Sep 20 '22 17:09

bassplayer7