Vertical Scrollbar leads to horizontal scrollbar - css

My CSS looks like this:
div.SOMECLASS {
position: absolute;
max-height: 300px
height: auto;
width: auto;
overflow: auto;
...
}
The div height and width scale automatically. The height has a fixed maximum though: as soon as this value is reached vertical scrollbars appear. This works all pretty swell.
Now the issue:
When the vertical scrollbar appears, it uses up around 10px of horizontal space, as the scrollbar will be placed inside the div.
However, the width is not autoscaled to allow for these additional 10-something pixels used up by the vertical scrollbars. As the horizontal width before the adding the vertical scrollbars was just exactly right for the content (as expected from the width:auto setting), the div now also displays horizontal scrollbars - to allow for the missing 10 pixels. This is silly.
How can I avoid having these horizontal scrollbars and just autoscale the width of the div to make the vertical scrollbars fit?
If possible I am looking for a solution which does not rely on just completely disabling horizontal scrolling, as this will probably be needed at some point (i.e. for certain inputs).

Just figured out a pretty passable solution (at least for my version of this problem).
I assume the issue with width: auto is that it behaves similarly to width: 100vw; the problem is that when the vertical scrollbar appears, the viewport width remains the same (despite the ~10px scrollbar), but the viewable area (as I'm calling it) is reduced by 10px.
Apparently defining width by percentage defines it in terms of this "viewable area", so changing your code to:
div.SOMECLASS {
position: absolute;
max-height: 300px
height: auto;
width: 100%;
overflow: auto;
...
}
should allow the content to rescale properly!
p.s. You can also instead add overflow-x: hidden, which will stop the horizontal scrollbar from appearing, instead simply cutting ~10px off of the right side of your div when the vertical scrollbar appears.

I found a solution which is working but far from perfect:
I added a padding-right : 15px to my div, to automatically grow the entire div. Now if the vertical scrollbars appear, they fit within the padding so the horizontal width is still ok.
Regretfully the padding of course also shows up when no vertical scrolling is needed, making my div just a tiny bit wider than it would have to be... :/ Well, in my eyes this is still preferable to unneeded horizontal scrollbars.

Often setting 100vw is the problem. Just remove it and your width will be 100%, which will be what you want anyways.

Number 1 search result on Google for my problem (similar to OP, but not the same).
Here is a common scenario for seemingly unnecessary-horizontal-scrollbar:
You have an element, say, a table, which uses auto-sizing. If the auto-sizing is done before all the rows are added, then it will not calculate enough room for a vertical-scrollbar. Doing the resize after adding rows fixed my issue -- even then, I needed a timeout
this.http.get('someEndPoint').subscribe(rows => {
this.rowData = rows;
setTimeout(()=>{sizeColumnsToFit()}, 50);
});

This bug (specific to Firefox) occurs even when not setting a fixed width.
For instance, if you have a vertically scrollable container div (overflow: auto;) inside a flexible wrapper div (display: inline-block;), then when you resize the window to be smaller than the content can wrap, first, a horizontal scrollbar will appear in your container div, and only after that, the flexible wrapper div will grow or eventually a secondary horizontal scrollbar will appear in your window.
The result is a useless horizontal scrollbar, that only can scroll the width of the vertical scrollbar:
In order to get rid of this issue, you could use the javascript-code from this example (tested in Firefox and Chromium):
<!DOCTYPE html>
<html>
<body>
<style type="text/css">
.page {height: 200px;width: 400px;overflow: auto;background-color: #ccc;border: 5px solid #000;margin: 5px;}
.wrapper {display: inline-block;min-width: 100%;margin: 20px;}
.scroller {overflow: auto;max-height: 100px;background-color: #f00;}
.content {min-height: 500px;min-width: 400px;background-color: #cfc;}
</style>
<div class="page">
<div class="wrapper">
<div class="scroller">
<div class="content">
The wrapper-div should expand to fit the scroller content.
Reduce the browser window width, and a useless horizontal scrollbar appears.
</div>
</div>
</div>
</div>
<div class="page">
<div class="wrapper">
<div class="scroller ensure-scrollbar-width-padding">
<div class="content">
But with the javascript-function, this is now fixed.
There is no horizontal scrollbar in the wrapper-div.
</div>
</div>
</div>
</div>
<script>
var ensureScrollbarWidthPadding = function(elem)
{
if(!parseInt(elem.scrollWidth) || !parseInt(elem.clientWidth) || !parseInt(elem.offsetWidth))
{
return; // no browser-support for this trick
}
var update = function()
{
// reset to as if not having any right-padding
elem.style.paddingRight = '0px';
// check if horizontal scrollbar appeared only because of the vertical scrollbar
if(elem.scrollWidth !== elem.clientWidth)
{
elem.style.paddingRight = (elem.offsetWidth - elem.clientWidth) + 'px';
}
else
{
elem.style.paddingRight = '0px';
}
};
window.addEventListener('resize', update, false);
window.addEventListener('load', update, false);
update();
return update;
};
(function()
{
var elems = document.getElementsByClassName('ensure-scrollbar-width-padding');
for(var i=0;i<elems.length;++i)
{
ensureScrollbarWidthPadding(elems[i]);
}
})();
</script>
</body>
</html>
The javascript function ensureScrollbarWidthPadding dynamically adds a padding-right to the vertically scrollable container, to ensure that the horizontal scrollbar will never appear.

I had the same issue and fixed it by setting up my CSS as follows:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
height: 100%;
}
body {
min-height: 100%;
width: 100%;
}
Here is also an awesome video that explains it very clearly, or the original article!

Related

100% height body is taller than 100vh, caused by Angular's router-outlet

I have an angular page, home, which is comprised of 2 components and a router-outlet
<div class="home-container">
<header></header>
<sub-header></sub-header>
<router-outlet></router-outlet>
</div>
I want the home-container above to always be, at a minimum, full screen height. The header should show, then the sub-header, then the contents of the router-outlet should always fill up at least the rest of the screen (or more if there's more content of course).
Normally this is easy but it seems the router-outlet is messing it up. Example can be seen http://plnkr.co/edit/56k9ZabLAGujBoX8Lsas , hit run and then click the "Heroes" link to route. In this example I don't want the Heroes div to be taller than the screen, and don't understand why it is.
My styles to accomplish this are. (assume router-outlet is on 'my-page')
html, body {
height: 100%;
}
.home-container {
height: 100%;
}
.my-page {
height: 100%;
}
My expectation here obviously is that home-container is full screen, shows header, shows sub-header, and that my-page then fills in at a minimum the rest of the vertical height.
What is actually happening though, is that there's a scroll bar with available height that appears equal to my header and sub-header.
This plnkr http://plnkr.co/edit/56k9ZabLAGujBoX8Lsas illustrates exactly my meaning. If you click Run and then the link for "Heroes" you will see the router-outlet contents, in this case heroes-list.component, with a green background. I do not understand why the green here is bleeding below the screen when everything is set to 100%
Update I have tried using all manner of different CSS attributes to different levels in this nesting. Including 100vh vs 100%, min-height vs height, and every combination of body/html/home-container/my-page. I have also tried the same with Angular's CSS :host, to the same result of no different
Update2 If I move it out of the element then everything behaves as you'd expect and there's no vertical scroll bar. Something about the router-outlet wrapper adds vertical space somewhere but I cannot figure out where or what is causing it.
Final Update The below answers might be useful for some applications but I ended up just solving it by giving the .my-page a specified height, just doing height: calc(100vh - $headerheight - $subheaderheight) which gets the job done
As far as I understand, 100% on a child will be equal to the size of the parents natural height. If you want to fill the space available, you really should be using flex unless you have a requirement to support IE9 and below.
I would update your Anchors to be contained in a div (or another wrapper)
<h1 class="title">Component Router</h1>
<div>
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
<a [routerLink]="['Heroes']">Heroes</a>
</div>
<router-outlet></router-outlet>
I would then utilize flexbox to allow the content to expand as required
.hero-list {
background-color: green;
height: 100%;
overflow:auto
}
undefined {
flex: 1;
}
body, html, my-app {
height: 100%;
}
my-app{
display: flex;
flex-flow: column;
}
Plunker to test: http://plnkr.co/edit/yE1KOZMr1pd5jQKlVYIN?p=preview
On chrome i still have scroll bars due to an 8px margin on body - this can easily be removed with CSS for a scroll free full height experience.
There are two causes that make your <body> element taller than 100% of the viewport:
Default margins of the <body> element that come from the browser's built-in styles and usually are 8px. This means that the <body> element will be as tall as the <html> element, but also will have 8px space above it and below it, causing the <html> element to overflow.
The top margin of the <h1> element "falls out" from the container due to margin collapsing. This makes the space above the <body> element equal to the default top margin of <h1> (about 21px instead of 8px).
Setting zero margin to <body> (part of ToTaTaRi's answer) helps you to solve the 1st issue. To solve the second one, you should make the <body> element or (probably better) the .my-app container establish the new Block Formatting Context. The easiest and most cross-browser way for this is setting the container overflow:hidden (other options are display:flow-root, which works for modern Chrome/Firefox, or column-count:1, which works in IE10+ and all modern browsers, you can compare nearly all the options in this live example).
First of all you should reset browser default styles at least somehow like this:
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
Then you could achive what you want without a flex layout if prefered through splitting the page into a header section and main content section with a preset division... So lets say the heading and the links go together into a container div with i.e. a height of 20% and the main content which is at the moment hold in a tag "undefined" gets a height of 80%, if you now set the height of the app container to 100% or 100vh it should work as expected!
EDIT (because the topic is still open...):
Have you tried this css code like explained above, works like charm!?
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body, my-app {
height: 100%;
height: 100vh;
}
h1 , h1 + div {
height: 10%;
height: 10vh;
}
undefined {
display: block;
background-color: green;
min-height: 80%;
min-height: 80vh;
}

Is it possible to calculate the Viewport Width (vw) without scrollbar? [duplicate]

This question already has answers here:
100vw causing horizontal overflow, but only if more than one?
(8 answers)
Closed 4 months ago.
As mentioned in the title, is it possible to calculate the vw without the scrollbars in css only?
For example, my screen has a width of 1920px. vw returns 1920px, great. But my actual body width is only something like 1903px.
Is there a way for me to retrieve the 1903px value with css only (not only for direct children of the body), or do I absolutely need JavaScript for this?
One way to do this is with calc. As far as i know, 100% is the width including scrollbars. So if you do:
body {
width: calc(100vw - (100vw - 100%));
}
You get the 100vw minus the width of the scrollbar.
You can do this with height as well, if you want a square that's 50% of the viewport for example (minus 50% of the scollbar width)
.box {
width: calc(50vw - ((100vw - 100%)/2))
height: 0
padding-bottom: calc(50vw - ((100vw - 100%)/2))
}
I do this by adding a line of javascript to define a CSS variable once the document has loaded:
document.documentElement.style.setProperty('--scrollbar-width', (window.innerWidth - document.documentElement.clientWidth) + "px");
then in the CSS you can use var(--scrollbar-width) to make any adjustments you need for different browsers with/without scrollbars of different widths. You can do something similar for the horizontal scrollbar, if needed, replacing the innerWidth with innerHeight and clientWidth with clientHeight.
COPY & PASTE solution
Here is an easy drop-in solution based on user11990065's answer to set a css variable --scrollbar-width and keep it updated on resizes.
It also gets calculated on DOMContentLoaded and load events so that you don't have to worry about size changes during the initial rendering phase.
You can just copy and paste it to your code as it is vanilla JS (or wrap it in a 'script' tag and paste it directly into your HTML code:
function _calculateScrollbarWidth() {
document.documentElement.style.setProperty('--scrollbar-width', (window.innerWidth - document.documentElement.clientWidth) + "px");
}
// recalculate on resize
window.addEventListener('resize', _calculateScrollbarWidth, false);
// recalculate on dom load
document.addEventListener('DOMContentLoaded', _calculateScrollbarWidth, false);
// recalculate on load (assets loaded as well)
window.addEventListener('load', _calculateScrollbarWidth);
If you have dynamic height changes in your page that might show / hide the scrollbar, you might want to look into Detect Document Height Change with which you can trigger the recalculation also on height changes.
As the value is calculated with JS and set to a fixed value you can use it in calc operations in your CSS, like so:
.full-width {
width: calc(100vw - var(--scrollbar-width));
}
This will give .full-width exactly the available width.
According to the specs, the viewport relative length units do not take scrollbars into account (and in fact, assume that they don't exist).
So whatever your intended behavior is, you cannot take scrollbars into account when using these units.
body { overflow: overlay; }
If you don't want to overcomplicate things, this might be sufficient in certain situations. At least it fixed my issues well enough, since there was enough whitespace between the content and the viewport edges (Windows scrollbar would overlap your 20-ish most right pixels).
Webkit browsers exclude the scrollbars, other include them in the returned width.
This may of course lead to problems: for instance if you have dynamically generated content with ajax that add height dynamically, Safari might switch from a layout to another during page visualization...
Ok, it doesn't happen often, but it's something to be aware about.
On mobile, less problems, cause scrollbars are generally not showed.
That's said, if your problem is calculate exactly the viewport width without scrollbars in all browser, as far as i know, a good method is this:
width = $('body').innerWidth();
having previously set:
body {
margin:0;
}
100vw = width of the screen with scrollbar
100% = width of the screen without scrollbar
It is always preferable to use calc(100% - 50px) while measuring the screen width. Even on windows browsers where scrollbar is visible directly, return the screen width differently when compare with macOS browsers.
It's possible just very "ugly" looking.
First you need to have this script running to get the scrollbar width into a css variable:
document.documentElement.style.setProperty('--scrollbar-width', (window.innerWidth - document.documentElement.clientWidth) + "px");
Now for example if you want "real" 80vw do this:
calc(0.8 * (100vw - var(--scrollbar-width)));
"real" 40vw
calc(0.4 * (100vw - var(--scrollbar-width)));
As long as you're not expecting any actual horizontal scroll, you could use this:
body {
overflow-x: hidden;
}
Which will then just hide the tiny amount of horizontal scroll caused by the auto scrolling Y.
I came across this question while looking for an answer for my case.
I wanted to use WordPress's solution to center a div on the viewport with the viewport's width just like .alignfull would normally.
Situation:
<html>
<body>
<div class="main">
<div class="continer">
<div class="row">
<div class="col-12">
<article>
<div class="content">
<div class="alignfull-or-alignwide">
<p>The content.</p>
</div>
</div>
</article>
</div>
</div>
</div>
</div>
</body>
</html>
My solution:
html {
width: 100vw;
overflow-x: hidden;
}
.alignfull-or-wide {
margin-right: calc(50% - 50vw);
margin-left: calc(50% - 50vw);
width: 100vw;
max-width: 100vw; // change this for wide or w/e.
}
This solved my problem by making the root of the document as wide as the viewport. With this, you essentially ignore the width of any scrollbar.
By setting to 100vw we eliminate the width of the scrollbar on any platform.
By setting the overflow parameter, we prevent any content from being rendered outside of the viewport.
By setting margins, we center the left side of the div to it's relative positioned parent. This usually is the center of the viewport too.
Then, the negative margin pulls it to the left side of the viewport.
By doing the same on the right we create the illusion of the div being centered on the page.
Also something to watch out for: scrollbar-width on csswg.
The only way I found it to work without messing your code with "calc"
is to make the container element size to 100vw; Adding a wrapper around the container for overflow-x; This will make the container to be fullwidth like if the scrollbar was over the content.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html{ overflow-y: scroll; }
html, body{ padding:0; margin: 0;}
#wrapper{ overflow-x: hidden; }
.row{ width: 100vw; }
.row:after{ clear: both; content: ''; display: block; overflow: hidden; }
.row-left{ background: blue; float: left; height: 40vh; width: 50vw; }
.row-right{ background: red; float: right; height: 40vh; width: 50vw; }
</style>
</head>
<body>
<div id="wrapper">
<div class="row">
<div class="row-left"></div>
<div class="row-right"></div>
</div>
</div>
</body>
</html>
The vw unit doesn't take the overflow-y scrollbar into account when overflow-y is set to auto.
Change it to overflow-y: scroll; and the vw unit will be the viewport with the scrollbar. Then you can subtract the scrollbar size from the vw value using calc(). You can also define the scrollbar width, so it will be browser-independent.
Only downside to take into account. If the content fits into the screen, the scrollbar is shown anyway. Possible solution is to change from auto to scroll in javascript.
No, there's no way to calculate the vw without the scrollbars in CSS.
However, there's a way to solve the 100vw ruined by the scrollbar on Windows issue. You have to create a full-width element, in this case row--full-width, that beelds out of a Flex container. This solution works on both Mac and Windows:
HTML:
<section>
<div class="container">
<div class="row--full-width"></div>
<div class="row">
<div class="card">
</div>
<div class="card">
</div>
</div>
</div>
</section>
Example: https://jsfiddle.net/ecmv6ho1/show
Code: https://jsfiddle.net/ecmv6ho1/
As you can see in the example above, the row--full-width element bleeds out of the container, and it aligns with the header even when there's a scrollbar.
Tested on Edge 18 (Win), Edge 88 (Win/Mac), and Chrome 88 (Win/Mac).
The easiest way is set the html & body to 100vw:
html, body{ width:100vw; overflow-x: hidden; overflow-y: auto; margin: 0; }
The only problem is the right-most will be cut a little if scrollbar is shown.
If the case were something similar to a slider:
As posted in many answers, width 100% doesn't take into account the scrollbar, while 100vw does. In the case of having many elements that need to take the width of the window and that are nested inside a container already with 100% window width (or whose natural block width would be such), you can use:
Display flex for container
Flex: 0 0 100% for child elements
It's not my solution, but helps me create dropdown fullwidth menu with absolute in relative element in not fullwith span.
We should get scroll with in css var in :root and then use it.
:root{
--scrollbar-width: calc(100vw - 100%);
}
div { margin-right: var(--scrollbar-width); }
https://codepen.io/superkoders/pen/NwWyee

Center Image inside div vertically using display table property

I'm trying to center an image vertically inside the div. I've read few other similar questions here on stackoverflow and decided to use this solution:
<div id="wrapper">
<div id="cell">
<img />
</div>
</div>
#wrapper {display:table;}
#cell {display:table-cell; vertical-align:middle;}
This works great for images smaller than the viewport size. Problem occurs when image is larger in height than the view-port. In that case wrapper div simply becomes the height of the image. And it overflows the page. How do I avoid that.
This wrapper div is part of view-port div. Viewport div is of fixed height and 100% width positioned absolute
#view-port{ height: 600px; width:100% }
EDIT: I think I caused some confusion regarding the question. I've created JSfiddle to explain what I mean
Here is a link: http://jsfiddle.net/sublime/fgTtj/
I want to vertically center the image inside #outer I dont have image dimensions, as you can see on fiddle, it works perfectly, but when #outer divs height goes less than image height, say 200 it cuts the image. I want to instead shrink that image to fit the outer div
This answer has been truncated and edited to meet the needs of the OP.
Using jQuery, here is what I would suggest.
You can get rid of several of your divs and just use a wrapper and your image. The problem with your code above is that you gave your outer div a set height at 300px. This means that it won't ever shrink smaller than that. I've written a small script to account for the window size as well
http://jsfiddle.net/fgTtj/40/
I've set up your HTML like so:
<div class="wrapper">
<img src='http://s13.postimg.org/b7hmfvhyv/css.jpg'></img>
</div>
CSS like so:
.wrapper {
position:relative;
width:100%;
height:300px;
background-color:blue;
overflow:hidden;
}
.wrapper img{
position:absolute;
max-width:100%;
max-height:100%;
}
and the new jQuery looks like this:
function center(){
var imgW = $('img').width();
var imgH = $('img').height();
var half_imgW = imgW / 2;
var half_imgH = imgH / 2;
$('img').css({
left: "50%",
top: "50%",
margin: "-" + half_imgH + "px 0 0 -" + half_imgW + "px"
});
}
$(document).ready(function(){
var wrapper_Height = $('.wrapper').height();
center();
$(window).resize(function(){
console.log(wrapper_Height);
var winH = $(this).height();
var wrapH = $('.wrapper').height();
if(winH <= wrapH){
$('.wrapper').height(winH);
} else {
if(wrapH <= wrapper_Height){
$('.wrapper').height(winH);
}
}
center();
});
});
You can resize this window in any direction and the image will stay centered and not cut off. This only works for one window at the moment, so you would have to adjust the script to accomodate more.
The awesome thing with this is that it will run in just about every browser, where display:table-cell does not work in older browsers such as IE6 and I think IE7.
What is the point of the display:table? You could leave it blank (or use display:inline-block), and add an overflow property.
#wrapper{
overflow:hidden;
}
If you want to be able to scroll to see the rest of the image:
#wrapper{
overflow:scroll;
}
If you don't want the image to extend the viewport height, set the max-height:
#cell img { max-height: 600px; }

Horizontal scroll bar won't go away?

Having trouble with a horizontal scroll bar that pops up.
My page is set up like so:
<html>
<head></head>
<body>
<article>
</article>
</body>
</html>
My css
article {
width:100%;
margin:0px auto;
padding:25px;
}
I'm also using Yahoo's Reset CSS. The trouble is the 100% on Article is giving me a horizontal scroll that I can't get rid of. I want it to stretch the length of the window with just a bit of space on the right and left.
The width property sets the width of the content, excluding padding, so the total width required by the element is all of the available width plus 2 times 25px.
Omit width: 100% (so that the default width: auto will be used).
This worked for me, I was having the same problem only in Firefox
body {
overflow-y: auto;
overflow-x: hidden;
}
100% Width + 25px padding = container.width+25px. Just add article { overflow-x:hidden } and it should hide it.

CSS - How to prevent the browser from showing scrollbars when a div goes outside of the window?

I have a centered wrapper with following CSS:
div.wrapper {
width: 1170px;
padding-left:30px;
margin-top: 80px;
margin-bottom:20px;
margin-left: auto;
margin-right: auto;
position:relative;
background-color:black; }
inside i have a div with following css:
position:absolute;
top:-26px;
left:517px;
height:63px;
z-index:3;
inside of this div is an image which has 759px width, that makes the wrapper grow larger and makes the browser show a v-scrollbar on lower display resolutions.
what i want is to make the image go outside the wrapper but prevent the browser from showing the scrollbar, so that the right side of the image is only shown if your browser window is large enough and the wrapper keeps its 1200px width. i can't make it a background image because it goes over some of the other content.
something that is compatible with >= IE7 would be nice.
i uploaded a pic of the page to show what i mean:
http://img153.imageshack.us/img153/6070/hpx.jpg
the blue box is the wrapper, it has 1200px width and is ALWAYS centered in the window (unless then window is smaller than 1200px, then it scrolls)
the red box is the image (the green bar is not part of it)
You can set overflow: hidden to the wrapper so that content that exceeds the dimensions of wrapper will not be shown.
see overflow
You are looking for #your_div { overflow: hidden; }, if you want your content to be hidden. Or #your_div { overflow: visible; } if you want your content visible outside the div.
The only method that springs to mind given your requirements is to move the inner element out of that wrapper div and position it in relation to the entire window:
<body>
<div class="abs">the div with the image</div>
<div class="wrapper">the wrapper div</div>
</body>
Unfortunately, this probably means you can't position it very well. You may need to use Javascript to get the width/height of the page and/or the position of the wrapper div, and calculate the offset accordingly. (You'll find questions on Stack Overflow for these bits.)
The problem lies with the img being inline. Not tested but you should 'display:block' the image and then float it or absolutely position it.

Resources