I've been trying to layout this page, but for the life of me, can't seem to get it to work the way I want.
Window = black
Titlebar = red
Content div = blue
Vertical scrollbar = green
Horizontal scrollbar = yellow
Min titlebar/content div width of 1024px, growing to window size.
I may be completely overthinking it and the answer may be way simpler than I'm attempting.
Basically I want to have a fixed titlebar div at the top of the page that never scrolls vertically. If it does not fit in the window horizontally, I want the horizontal scrollbar to scroll both the titlebar and content. If the content div is taller than the window height, I want it to scroll, otherwise I want it to extend to the bottom of the page.
For the most part, I'm under next to no restrictions on how these divs may be set, so imagine there is a blank slate.
Needs to work on modern browsers only on recent OSes. Ideally only a CSS/HTML fix, but will consider some JS if absolutely required. Needs visible scrollbars (some versions I tried the scrollbars were off outside the window scope, ie, not just mousewheel scroll, but click and drag scroll).
I have to edit my answer, because after reading Lokesh Suthar's answer I finally understood your question! ;-)
There is no CSS solution!
You'll find the reason in the spec (http://www.w3.org/TR/CSS2/visuren.html#fixed-positioning):
Fixed positioning is a subcategory of absolute positioning. The only difference is that for a fixed positioned box, the containing block is established by the viewport. For continuous media, fixed boxes do not move when the document is scrolled.
So you have to go with a JS solution like the one Lokesh Suthar has linked to in his answer.
A personal note:
Normally web designer try to avoid horizontal scrollbars at all costs!
They are "bad" for usability and most users hate to scroll horizontally.
And instead of making a fixed positioned element wider than the viewport you should expand its height.
Remember: Using a JS solution on this will make content unreachable/ not visible if JS is disabled!
Pure CSS Solution.
Here's my updated answer. Please check.
Demo link below:
Fiddle
HTML
<div id="title-bar">Title Bar</div>
<div id="content">Contents</div>
CSS
html, body {
margin:0;
padding:0;
height:100%;
}
#title-bar, #content {
min-width:1024px;
width:100%;
}
#title-bar {
position:fixed;
top:0;
background:#CC0000;
height:50px;
color:#fff;
}
#content {
top:50px;
position:relative;
background:#9EC2E3;
height:calc(100% - 50px);
overflow:auto;
}
Just let me know if you have concerns.
I think this may work for you...
Working Example
JS:
$(window).scroll(function () { // on scroll
var win = $(window);
var title = $('.title');
var winWidth = $(window).innerWidth();
var titleWidth = title.width();
if (win.scrollLeft() >= titleWidth - winWidth) { // if scrolled to the right further than .title is wide minus the window's width
title.addClass('fixed'); // add the fixed class
title.offset({ //keep the title bar at the top
top: win.scrollTop(),
});
} else { // if not
title.removeClass('fixed'); // removed class fixed
title.offset({ // keep the title bar at the top anyway
top: win.scrollTop(),
});
}
});
CSS:
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
html, body {
width: 1024px;
height:100%
}
.title {
background:red;
position: absolute;
z-index:2;
min-width: 100%;
}
#content {
background: blue;
padding-top:50px;
min-width:1024px;
min-height:100%;
}
.fixed {
position: fixed;
right: 0;
}
API documentation:
.scroll()
.innerWidth()
.width()
.scrollLeft()
.offset()
.addClass()
.removeClass()
With CSS:
In short, it is not possible with position: fixed;.
As already mentioned by other answers, it is not possible to force a fixed div to scroll, because the div becomes positioned in relation to the viewport (thanks #Netsurfer for digging up the link), and there is no way for us to manipulate this.
Alternative 1: You could set overflow of the body to hidden (thereby hiding browser scrollbars) and add a new wrapper div that fills the entire viewport by using viewport units (vh and vw). You would then nest your titlebar and content divs within this wrapper and give it a horizontal scrollbar. Then you would absolutely position your titlebar in relation to a new titlebar wrapper div, while wrapping your content in a div with 100% (minus the titlebar) height and a vertical scrollbar.
See jsfiddle example.
This approach is rather ugly when you consider all the wrappers... also, when you apply a min-width of 1024 pixels to the content, the vertical scrollbar will move out of the viewport when viewed on smaller screens (as you mentioned in your post). You could position the scrollbar on the left side using direction: rtl;, but the scrollbar will still go out of view when scrolling to the right.
See jsfiddle example with scrollbar on left.
All in all it is not a great solution which would need to be heavily tested for cross-browser support any time anything is changed. Currently it works in Chrome 33 (which I am using) and I have also succesfully tested it in Firefox 27, Internet Explorer 11 and Opera 19. Safari 5.1 (windows) does not like it, but it should work on the newer Mac versions. For Safari 5.1 you can try changing to % heights and dropping the css calc() method, but you'll probably have problems scrolling the entire content.
Alternative 2: Wait. In the future you may be able to use position: sticky; to achieve exactly what you want (assuming this new property ever gains complete browser support). You can see it in action with chrome if you enable the "Enable experimental Web Platform features" option under "chrome://flags/".
See jsfiddle example.
With jQuery:
With jQuery this becomes a trivial task if you forget about position: fixed;, and does not require much code. All you would have to do is position the titlebar div absolutely and then tell it to move every time the window is scrolled:
$window.scroll(function() {
$(".title").css('top', $window.scrollTop() + "px");
});
Using .css() is slightly faster than using .offset() (see benchmark tests).
If JS is disabled the titlebar will simply scroll out of view.
See jsfiddle example.
Considering how easy this is with jQuery, I would suggest using that approach.
I think this should answer your query.
CLICK ME
Basically the fellow is trying moving the fixed nav with scroll events(playing with left property as he says)
I used position absolute to set height in percentage.
like for titlebar ,
position:fixed;
height:6%;
you can remove wrapper if you don't want to use,
Click for demo
Let me know more if it need some changes
You have to use a combination of CSS and JavaScript. As the others stated, a fixed element does not scroll and you cannot choose that it should scroll horizontally but not vertically. So there comes the JS.
This is the shortest form I could think of. This should work on mobile devices, too. It works with a inner div in the fixed element, which is positioned absolute and reacts to the windows scroll event.
Here is the codepen example: http://codepen.io/HerrSerker/pen/AJHyf
This just works with a fixed height header. If your header is not fixed in height, you have to add some JavaScript, that measures the height of the header and adds
HTML
<div id="maker"></div>
<header><div id="header_inner">Lorem ipsum dolor sit amet.</div></header>
<main><div id="#main_inner">Lorem ipsum dolor sit amet ...</div></main>
CSS
html,body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body {
overflow: auto;
}
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
#maker {
width: 1024px;
height: 1px;
margin-top: -1px;
background: red;
}
header {
position: fixed;
min-width: 1024px;
background: black;
color:white;
width: 100%;
height: 50px;
}
#header_inner {
padding: 10px;
}
main {
padding: 0px;
padding-top: 50px;
min-height: 100%;
min-width: 1024px;
background: gold;
color: brown;
}
#main_inner {
padding: 20px;
}
JavaScript
(function() {
var headerInner = document.getElementById('header_inner');
headerInner.style.position = 'absolute';
var scrollReact = function() {
headerInner.style.left = '-'+self.pageXOffset+'px';
}
if ('addEventListener' in self) {
self.addEventListener('scroll', scrollReact);
} else if (typeof self.attachEvent == 'function') {
self.attachEvent('scroll', scrollReact );
}
}())
Related
I want to make body have 100% of the browser height. Can I do that using CSS?
I tried setting height: 100%, but it doesn't work.
I want to set a background color for a page to fill the entire browser window, but if the page has little content I get a ugly white bar at the bottom.
Try setting the height of the html element to 100% as well.
html,
body {
height: 100%;
}
Body looks to its parent (HTML) for how to scale the dynamic property, so the HTML element needs to have its height set as well.
However the content of body will probably need to change dynamically.
Setting min-height to 100% will accomplish this goal.
html {
height: 100%;
}
body {
min-height: 100%;
}
As an alternative to setting both the html and body element's heights to 100%, you could also use viewport-percentage lengths.
5.1.2. Viewport-percentage lengths: the ‘vw’, ‘vh’, ‘vmin’, ‘vmax’ units
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.
In this instance, you could use the value 100vh - which is the height of the viewport.
Example Here
body {
height: 100vh;
padding: 0;
}
body {
min-height: 100vh;
padding: 0;
}
This is supported in most modern browsers - support can be found here.
If you have a background image then you will want to set this instead:
html{
height: 100%;
}
body {
min-height: 100%;
}
This ensures that your body tag is allowed to continue growing when the content is taller than the viewport and that the background image continues to repeat/scroll/whatever when you start scrolling down.
Remember if you have to support IE6 you will need to find a way to wedge in height:100% for body, IE6 treats height like min-height anyway.
If you want to keep the margins on the body and don't want scroll bars, use the following css:
html { height:100%; }
body { position:absolute; top:0; bottom:0; right:0; left:0; }
Setting body {min-height:100%} will give you scroll bars.
See demo at http://jsbin.com/aCaDahEK/2/edit?html,output .
After testing various scenarios, I believe this is the best solution:
html {
width: 100%;
height: 100%;
display: table;
}
body {
width: 100%;
display: table-cell;
}
html, body {
margin: 0;
padding: 0;
}
It is dynamic in that the html and the body elements will expand automatically if their contents overflow. I tested this in the latest version of Firefox, Chrome, and IE 11.
See the full fiddle here (for you table haters out there, you can always change it to use a div):
https://jsfiddle.net/71yp4rh1/9/
With that being said, there are several issues with the answers posted here.
html, body {
height: 100%;
}
Using the above CSS will cause the html and the body element to NOT automatically expand if their contents overflow as shown here:
https://jsfiddle.net/9vyy620m/4/
As you scroll, notice the repeating background? This is happening because the body element's height has NOT increased due to its child table overflowing. Why doesn't it expand like any other block element? I'm not sure. I think browsers handle this incorrectly.
html {
height: 100%;
}
body {
min-height: 100%;
}
Setting a min-height of 100% on the body as shown above causes other problems. If you do this, you cannot specify that a child div or table take up a percentage height as shown here:
https://jsfiddle.net/aq74v2v7/4/
Hope this helps someone. I think browsers are handling this incorrectly. I would expect the body's height to automatically adjust growing larger if its children overflow. However, that doesn't seem to happen when you use 100% height and 100% width.
html, body
{
height: 100%;
margin: 0;
padding: 0;
}
A quick update
html, body{
min-height:100%;
overflow:auto;
}
A better solution with today's CSS
html, body{
min-height: 100vh;
overflow: auto;
}
What I use on the start of literally every CSS file I use is the following:
html, body{
margin: 0;
padding: 0;
min-width: 100%;
width: 100%;
max-width: 100%;
min-height: 100%;
height: 100%;
max-height: 100%;
}
The margin of 0 ensures that the HTML and BODY elements aren't being auto-positioned by the browser to have some space to the left or right of them.
The padding of 0 ensures that the HTML and BODY elements aren't automatically pushing everything inside them down or right because of browser defaults.
The width and height variants are set to 100% to ensure that the browser doesn't resize them in anticipation of actually having an auto-set margin or padding, with min and max set just in case some weird, unexplainable stuff happens, though you probably dont need them.
This solution also means that, like I did when I first started on HTML and CSS several years ago, you won't have to give your first <div> a margin:-8px; to make it fit in the corner of the browser window.
Before I posted, I looked at my other fullscreen CSS project and found that all I used there was just body{margin:0;} and nothing else, which has worked fine over the 2 years I've been working on it.
Hope this detailed answer helps, and I feel your pain. In my eyes, it is dumb that browsers should set an invisible boundary on the left and sometimes top side of the body/html elements.
Here:
html,body{
height:100%;
}
body{
margin:0;
padding:0
background:blue;
}
You can also use JS if needed
var winHeight = window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight;
var pageHeight = $('body').height();
if (pageHeight < winHeight) {
$('.main-content,').css('min-height',winHeight)
}
I would use this
html, body{
background: #E73;
min-height: 100%;
min-height: 100vh;
overflow: auto; // <- this is needed when you resize the screen
}
<html>
<body>
</body>
</html>
The browser will use min-height: 100vh and if somehow the browser is a little older the min-height: 100% will be the fallback.
The overflow: auto is necessary if you want the body and html to expand their height when you resize the screen (to a mobile size for example)
CSS Height That Works in Both Modern and Legacy Browsers
Most of the other solutions posted here will not work well in legacy browsers! And some of the code people posted will cause a nasty overflow of text beyond 100% height in modern browsers where text flows past background colors, which is bad design! So please try my code solution instead.
The CSS code below should support flexible web page height settings correctly in all known browsers, past and present:
html {
height: 100%; /* Fallback CSS for IE 4-6 and older browsers. Note: Without this setting, body below cannot achieve 100% height. */
height: 100vh;/* Overrides 100% height in modern HTML5 browsers and uses the viewport's height. Only works in modern HTML5 browsers */
}
body {
height: auto; /* Allows content to grow beyond the page without overflow */
width: auto; /* Allows content to grow beyond the page without overflow */
min-height: 100%; /* Starts web page with 100% height. Fallback for IE 4-6 and older browsers */
min-height: 100vh;/* Starts web page with 100% height. Uses the viewport's height. Only works in modern HTML5 browsers */
overflow-y: scroll;/* Optional: Adds an empty scrollbar to the right margin in case content grows vertically, creating a scrollbar. Allows for better width calculations, as the browser pre-calculates width before scrollbar appears, avoiding page content shifting.*/
margin: 0;
padding: 0;
background:yellow;/* FOR TESTING: Next add a large block of text or content to your page and make sure this background color always fills the screen as your content scrolls off the page. If so, this works. You have 100% height with flexible content! */
}
NOTES ON THE CODE ABOVE
In many older, as well as newer browsers, if you do not set 100% height on the <html> selector, body will never achieve 100% height! So that is critical here.
The new viewport units ("vh") are redundant on the body selector and not necessary as long as you have set html selector to a height of either 100% or 100vh. The reason is the body always derives its values from the html parent. The exception is a few very old browsers from the past, so its best to set some height value for the body.
Some modern browsers using the body selector will not know how to inherit the viewport height directly. So again, always set your html selector to 100% height! You can still use "vh" units in body to bypass the parent html value and get its property dimensions directly from the viewport in most modern browsers, however. But again, its optional if the parent or root html selector has 100% height, which body will always inherit correctly.
Notice I've set body to height:auto, not height:100%. This collapses the body element around content initially so it can grow as content grows. You do NOT want to set body height and width to 100%, or specific values as that limits content to the body's current visual dimensions, not its scrollable dimensions. Anytime you assign body height:100%, as soon as content text moves beyond the browser's height, it will overflow the container and thus any backgrounds assigned to the original viewport height, creating an ugly visual! height:auto is your best friend in CSS!
But you still want body to default to 100% height, right? That is where min-height:100% works wonders! It will not only allow your body element to default to 100% height, but this works in even the oldest browsers! But best of all, it allows your background to fill 100% and yet stretch farther down as content with height:auto grows vertically.
Using overflow:auto properties are not needed if you set height:auto on the body. That tells the page to let content expand height to any dimension necessary, even beyond the viewport's height, if it needs to and content grows longer than the viewport page display. It will not break out of the body dimensions. And it does allow scrolling as needed. overflow-y:scroll allows you to add an empty scrollbar to the right of the page content by default in every web browser. The scrollbar only appear inside the scroll bar area if content extends beyond 100% height of the viewport. This allows your page width, and any margins or paddings to be calculated by the browser beforehand and stop the pages from shifting as users view pages that scroll and those that do not. I use this trick often as it sets the page width perfectly for all scenarios and your web pages will never shift and load lightning fast!
I believe height:auto is the default on body in most UA browser style sheets. So understand most browsers default to that value, anyway.
Adding min-height:100% gives you the default height you want body to have and then allows the page dimensions to fill the viewport without content breaking out of the body. This works only because html has derived its 100% height based on the viewport.
The two CRITICAL pieces here are not the units, like % or vh, but making sure the root element, or html, is set to 100% of the viewport height. Second, its important that body have a min-height:100% or min-height:100vh so it starts out filling the viewport height, whatever that may be. Nothing else beyond that is needed.
STYLING HEIGHT FOR LEGACY BROWSERS
Notice I have added "fallback" properties for height and min-height, as many browsers pre-2010 do not support "vh" viewport units. It's fun to pretend everyone in the web world uses the latest and greatest but the reality is many legacy browsers are still around today in big corporate networks and many still use antiquated browsers that do not understand those new units. One of the things we forget is many very old browsers do not know how to fill the the viewport height correctly. Sadly, those legacy browsers simply had to have height:100% on both the html element and the body as by default they both collapsed height by default. If you did not do that, browser background colors and other weird visuals would flow up under content that did not fill the viewport. The example above should solve all that for you and still work in newer browsers.
Before modern HTML5 browsers (post-2010) we solved that by simply setting height:100% on both the html and body selectors, or just min-height:100% on the body. So either solution allows the code above to work in over 20+ years of legacy web browsers rather than a few created the past couple of years. In old Netscape 4 series or IE 4-5, using min-height:100% instead of height:100% on the body selector could still cause height to collapse in those very old browsers and cause text to overflow background colors. But that would be the one issue I could see with this solution.
Using my CSS solution, you now allow your website to be viewed correctly in 99.99% of browsers, past and present rather than just 60%-80% of browsers built the past few years.
Good Luck!
Try
<html style="width:100%; height:100%; margin: 0; padding: 0;">
<body style="overflow:hidden; width:100%; height:100%; margin:0; padding:0;">
Please check this:
* {margin: 0; padding: 0;}
html, body { width: 100%; height: 100%;}
Or try new method Viewport height :
html, body { width: 100vw; height: 100vh;}
Viewport:
If your using viewport means whatever size screen content will come full height fo the screen.
If you don't want the work of editing your own CSS file and define the height rules by yourself, the most typical CSS frameworks also solve this issue with the body element filling the entirety of the page, among other issues, at ease with multiple sizes of viewports.
For example, Tacit CSS framework solves this issue out of the box, where you don't need to define any CSS rules and classes and you just include the CSS file in your HTML.
html {
background: url(images/bg.jpg) no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
min-height: 100%;
}
html body {
min-height: 100%
}
Works for all major browsers: FF, Chrome, Opera, IE9+. Works with Background images and gradients. Scrollbars are available as content needs.
For the true purists, this one respects the default margins of the browser, and prevents the undesired scroll generated by the other methods, besides growing if the content grows. Tested in Chrome, Safari and Firefox. The backgrounds are just for show...
html {
display: flex;
flex-direction: column;
height: 100%;
background: red;
}
body {
flex:1;
background: green;
}
Only with 1 line of CSS… You can get this done.
body{ height: 100vh; }
all answers are 100% correct and well explained,
but i did something good and very simple to make it responsive.
here the element will take 100% height of view port but when it comes to mobile view it don't look good specially on portrait view ( mobile ), so when view port is getting smaller the element will collapse and overlap on each other. so to make it little responsive here is code.
hope someone will get help from this.
<style>
.img_wrap{
width:100%;
background: #777;
}
.img_wrap img{
display: block;
width: 100px;
height: 100px;
padding: 50px 0px;
margin: 0 auto;
}
.img_wrap img:nth-child(2){
padding-top: 0;
}
</style>
<div class="img_wrap">
<img src="https://i.pinimg.com/originals/71/84/fc/7184fc63db0516a00e7d86900d957925.jpg" alt="">
<img src="https://i.pinimg.com/originals/71/84/fc/7184fc63db0516a00e7d86900d957925.jpg" alt="">
</div>
<script>
var windowHeight = $(window).height();
var elementHeight = $('.img_wrap').height();
if( elementHeight > windowHeight ){
$('.img_wrap').css({height:elementHeight});
}else{
$('.img_wrap').css({height:windowHeight});
}
</script>
here is JSfiddle Demo.
I style the div container - usually the sole child of the body with the following css
.body-container {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
height: 100%;
display: flex;
flex-direction: column;
overflow-y: auto;
}
Over 20 answers later and none seem to have mentioned the factor that I found was the most crucial - the markup.
After trying basically every answer in this question and a few others, I restructured my markup to something like the following:
<body>
<div class="section1">
<nav>
</nav>
...
</div>
<div class="section2">
</div>
</body>
Essentially, it requires two different outer containers. The first container is for the purpose of containing the navbar and extending the background colour/image all the way to the height of the browser, and the second one for containing everything "below the fold" - including the second background colour/image.
This solution allows the first container's background to expand all the way to the bottom while keeping the second container free to take up as much space as it needs.
From this point on, the only CSS needed to get the result both I and the original question wanted is the following:
body {
height: 100%;
}
.section1 {
height: 100%;
background: black; /* for demo purposes */
}
.section2 {
background: white; /* for demo purposes */
}
Here Update
html
{
height:100%;
}
body{
min-height: 100%;
position:absolute;
margin:0;
padding:0;
}
About the extra space at the bottom: is your page an ASP.NET application? If so, there is probably a wrapping almost everything in your markup. Don't forget to style the form as well. Adding overflow:hidden; to the form might remove the extra space at the bottom.
CSS3 has a new method.
height:100vh
It makes ViewPort 100% equal to the height.
So your Code should be
body{
height:100vh;
}
I'm trying to build a website that has lots of boxes that are of equal width and height. For example, I have a page that has 2 equal size boxes side by side.
The simple solution was to set the width and height to 50vw. This works great until there is a scroll bar. I've Googled around for hours and can't understand why on earth vw and vh would include the scrollbars as part of the viewport.
Here's a sample of my issue
HTML
<div class="container">
<div class="box red"></div>
<div class="box green"></div>
</div>
<div class="lotta-content"></div>
CSS
body {
margin: 0;
padding: 0;
}
.container {
width: 100vw;
}
.box {
float: left;
width: 50vw;
height: 50vw;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.lotta-content {
height: 10000px;
}
Notice the unwanted horizontal scrollbar
https://jsfiddle.net/3z887swo/
One possible solution would be to use percentages for the widths, but vw for the height, but it won't ever be a perfect box which isn't the worst thing in the world, but still not ideal. Here's a sample
https://jsfiddle.net/3z887swo/1/
Does anyone know why vw/vh include scrollbars as part of the viewport? Also, if someone has a better solution than my own, I'd love to hear it. I'm looking for a pure CSS solution. I rather not have javascript.
I have a different answer, and feel the need to share my frustration
BECAUSE STANDARD-MAKERS ARE STUPID
(committees, in general, always are)
One simple (simplicistic) workaround is keeping the scrollbar always around and be dealt with it
html,body {margin:0;padding:0}
html{overflow-y:scroll}
(use overflow-x for a layout that uses vh)
I believe they seriously screwed the pooch on this one.
It would be convenient if viewport units didn't include cause scrollbars but it is the display size (screen) after all. Have look at this solution with a pseudo element though:
http://www.mademyday.de/css-height-equals-width-with-pure-css.html
Makes for a square in your example as well:
https://jsfiddle.net/3z887swo/4/
.box {
float: left;
width: 50%;
}
.box::before {
content: "";
display: block;
padding-top: 100%;
}
Edit - if anyone is wondering why this works (vertical padding responding to the original element's width)... that's basically how it's defined in the specification:
The percentage is calculated with respect to the width of the generated box's containing block, even for 'padding-top' and 'padding-bottom'.
http://www.w3.org/TR/CSS2/box.html#padding-properties
After coming across my own answer, I think it needed some refinement. Semantic ambiguity is why I replaced the word "include" with "cause" at the top. Because it's more the fact that vw units only take the viewport size into account - not including any scrollbar and causing overflow and a scrollbar in the other direction when its width is added to 100vw (making the total space that is needed the viewport plus scrollbar width, exceeding the screen).
As with the question here, the best way to handle vw units is likely to avoid them if you can because they just aren't very compatible with desktop browser (that don't have overlaying scrollbars).
I edited out the idea that included a CSS variable, however hopeful it seemed.
html { overflow-x: hidden; }
seems to work
This question is old, and answered well above, so I'm going to focus on obtaining scrollbar width to then be used to calc element widths, as that's why I landed here. Hopefully this will help other Googlers.
A sloppy CSS solution
I started writing the pure CSS solution based on the calculation below but once you start factoring in elements inside variable width containers, especially when they aren't 100% of the visible width, the calc functions start getting convoluted and unreadable.
For anybody interested, this calc on the root element (<html>) (assuming the doc is full width and no wider) will give you the scrollbar width or 0 when no scrollbar is displayed.
calc( 100vw - 100% );
A robust solution
Personally, I wouldn't battle CSS on this one. Use the right tool for the job:
(function get_scrollbar_width() {
// Get window width including scrollbar.
const withScrollBar = window.innerWidth;
// Get window width excluding scrollbar.
const noScrollBar = document.querySelector("html").getBoundingClientRect().width;
// Calc the scrollbar width.
scrollbarWidth = parseInt((withScrollBar - noScrollBar), 10) + 'px';
// Update the CSS custom property value.
let root = document.documentElement;
root.style.setProperty('--scrollbar', scrollbarWidth);
})();
:root {
--scrollbar: 0px;
}
body {
overflow: scroll;
}
.demobox {
display: grid;
grid: auto / var(--scrollbar) max-content;
width: calc(10em + var(--scrollbar) );
margin: 0 auto;
}
.demobox > div {
background: red;
}
.demobox > p {
padding: 1em;
text-align: center;
width: 10em;
}
<div class="demobox">
<div></div>
<p>
This red grid cell represents the scrollbar width as set
on the CSS custom property by the JavaScript function.
</p>
</div>
I have a solution here. It'll include the scrollbar width when you use 100vw, right? so if we can't make it right, then we can remove the scrollbar, make it invisible. like this: Hide scroll bar, but while still being able to scroll
I have a website with center-aligned DIV. Now, some pages need scrolling, some don't. When I move from one type to another, the appearance of a scrollbar moves the page a few pixels to the side. Is there any way to avoid this without explicitly showing the scrollbars on each page?
overflow-y:scroll is correct, but you should use it with the html tag, not body or else you get a double scrollbar in IE 7
So the correct css would be:
html {
overflow-y: scroll;
}
Wrap the content of your scrollable element into a div and apply padding-left: calc(100vw - 100%);.
<body>
<div style="padding-left: calc(100vw - 100%);">
Some Content that is higher than the user's screen
</div>
</body>
The trick is that 100vw represents 100% of the viewport including the scrollbar. If you subtract 100%, which is the available space without the scrollbar, you end up with the width of the scrollbar or 0 if it is not present. Creating a padding of that width on the left will simulate a second scrollbar, shifting centered content back to the right.
Please note that this will only work if the scrollable element uses the page's entire width, but this should be no problem most of the time because there are only few other cases where you have centered scrollable content.
html {
overflow-x: hidden;
margin-right: calc(-1 * (100vw - 100%));
}
Example. Click "change min-height" button.
With calc(100vw - 100%) we can calculate the width of the scrollbar (and if it is not displayed, it will be 0). Idea: using negative margin-right, we can increase the width of <html> to this width. You will see a horizontal scroll bar — it should be hidden using overflow-x: hidden.
I think not. But styling body with overflow: scroll should do. You seem to know that, though.
With scroll always being shown, maybe be not good for layout.
Try to limit body width with css3
body {
width: calc(100vw - 34px);
}
vw is the width of the viewport (see this link for some explanation)
calc calculate in css3
34px stands for double scrollbar width (see this for fixed or this to calculate if you don't trust fixed sizes)
If changing size or after loading some data it is adding the scroll bar then you can try following, create class and apply this class.
.auto-scroll {
overflow-y: overlay;
overflow-x: overlay;
}
I don't know if this is an old post, but i had the same problem and if you want to scroll vertically only you should try overflow-y:scroll
body {
scrollbar-gutter: stable both-edges;
}
New css spec that will help with scrollbar repositioning is on its way:
https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-gutter
Summary
I see three ways - each with their own quirks:
scrollbar-gutter as mentioned by Markus T.
overflow: overlay as mentioned by kunalkamble
Add spacing with calc(100vw - 100%) as mentioned Rapti
Here is a StackBlitz demo
Press the "Toggle height" to see the content shift.
scrollbar-gutter
This has limited support but with a #support media query we can use a combination of this and overflow-y: scroll:
html {
overflow-y: scroll;
}
#supports (scrollbar-gutter: stable) {
html {
overflow-y: auto;
scrollbar-gutter: stable;
}
}
In this way content will never shift.
The "problem" with this solution is that there is always a fixed space for the scrollbar.
overflow: overlay
Limited support and it obviously hides anything it overlays. Special care is needed to make sure nothing vital is hidden (also on zoom and text size changes).
Can be combined with scrollbar-gutter:
html {
overflow-y: scroll;
}
#supports (scrollbar-gutter: stable) {
html {
overflow-y: auto;
scrollbar-gutter: stable;
}
}
#supports (overflow-y: overlay) {
html {
overflow-y: overlay;
scrollbar-gutter: auto;
}
}
It is possible to do some negative margin and overflow-x: hidden but this has a risk of hiding vital content under certain situations. Small screen, custom font/zoom size, browser extensions, etc.
calc(100vw - 100%)
This can be done with RTL support like this:
html[dir='ltr'] main {
padding-left: calc(100vw - 100%);
}
html[dir='rtl'] main {
padding-right: calc(100vw - 100%);
}
Where <main> in this case would be the container for the centered content.
Content here will not shift as long as the centered container is smaller than <main>. But as soon as it is 100% of the container a padding will be introduced. See the StackBlitz demo and click "Toggle width".
The "problem" with this solution is that you need media queries to prevent padding on "small screens" and that even on small screens - when the scrollbar should be visible - some shifting will occur because there is no room for 100% content and a scrollbar.
Conclusion
Use scrollbar-gutter perhaps combined with overlay. If you absolutely don't want empty spacing, try the calc solution with media queries.
Simply setting the width of your container element like this will do the trick
width: 100vw;
This will make that element ignore the scrollbar and it works with background color or images.
#kashesandr's solution worked for me but to hide horizontal scrollbar I added one more style for body. here is complete solution:
CSS
<style>
/* prevent layout shifting and hide horizontal scroll */
html {
width: 100vw;
}
body {
overflow-x: hidden;
}
</style>
JS
$(function(){
/**
* For multiple modals.
* Enables scrolling of 1st modal when 2nd modal is closed.
*/
$('.modal').on('hidden.bs.modal', function (event) {
if ($('.modal:visible').length) {
$('body').addClass('modal-open');
}
});
});
JS Only Solution (when 2nd modal opened from 1st modal):
/**
* For multiple modals.
* Enables scrolling of 1st modal when 2nd modal is closed.
*/
$('.modal').on('hidden.bs.modal', function (event) {
if ($('.modal:visible').length) {
$('body').addClass('modal-open');
$('body').css('padding-right', 17);
}
});
I've solved the issue on one of my websites by explicitly setting the width of the body in javascript by the viewport size minus the width of the scrollbar. I use a jQuery based function documented here to determine the width of the scrollbar.
<body id="bodyid>
var bodyid = document.getElementById('bodyid');
bodyid.style.width = window.innerWidth - scrollbarWidth() + "px";
Extending off of Rapti's answer, this should work just as well, but it adds more margin to the right side of the body and hides it with negative html margin, instead of adding extra padding that could potentially affect the page's layout. This way, nothing is changed on the actual page (in most cases), and the code is still functional.
html {
margin-right: calc(100% - 100vw);
}
body {
margin-right: calc(100vw - 100%);
}
Expanding on the answer using this:
body {
width: calc(100vw - 17px);
}
One commentor suggested adding left-padding as well to maintain the centering:
body {
padding-left: 17px;
width: calc(100vw - 17px);
}
But then things don't look correct if your content is wider than the viewport. To fix that, you can use media queries, like this:
#media screen and (min-width: 1058px) {
body {
padding-left: 17px;
width: calc(100vw - 17px);
}
}
Where the 1058px = content width + 17 * 2
This lets a horizontal scrollbar handle the x overflow and keeps the centered content centered when the viewport is wide enough to contain your fixed-width content
If the width of the table won't change, you can set the width of the element (such as tbody) that contains the scrollbar > 100% (allowing extra space for the scrollbar) and set overflow-y to "overlay" (so that the scrollbar stays fixed, and won't shift the table left when it appears). Also set a fixed height for the element with the scrollbar, so the scrollbar will appear once the height is exceeded. Like so:
tbody {
height: 100px;
overflow-y: overlay;
width: 105%
}
Note: you will have to manually adjust the width % as the % of space the scrollbar takes up will be relative to your table width (ie: smaller width of table, more % required to fit the scrollbar, as it's size in pixels is constant)
A dynamic table example:
function addRow(tableID)
{
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
var colCount = table.rows[0].cells.length;
for(var i=0; i<colCount; i++)
{
var newRow = row.insertCell(i);
newRow.innerHTML = table.rows[0].cells[i].innerHTML;
newRow.childNodes[0].value = "";
}
}
function deleteRow(row)
{
var table = document.getElementById("data");
var rowCount = table.rows.length;
var rowIndex = row.parentNode.parentNode.rowIndex;
document.getElementById("data").deleteRow(rowIndex);
}
.scroll-table {
border-collapse: collapse;
}
.scroll-table tbody {
display:block;
overflow-y:overlay;
height:60px;
width: 105%
}
.scroll-table tbody td {
color: #333;
padding: 10px;
text-shadow: 1px 1px 1px #fff;
}
.scroll-table thead tr {
display:block;
}
.scroll-table td {
border-top: thin solid;
border-bottom: thin solid;
}
.scroll-table td:first-child {
border-left: thin solid;
}
.scroll-table td:last-child {
border-right: thin solid;
}
.scroll-table tr:first-child {
display: none;
}
.delete_button {
background-color: red;
color: white;
}
.container {
display: inline-block;
}
body {
text-align: center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="test_table.css">
</head>
<body>
<h1>Dynamic Table</h1>
<div class="container">
<table id="data" class="scroll-table">
<tbody>
<tr>
<td><input type="text" /></td>
<td><input type="text" /></td>
<td><input type="button" class="delete_button" value="X" onclick="deleteRow(this)"></td>
</tr>
</tbody>
</table>
<input type="button" value="Add" onclick="addRow('data')" />
</div>
<script src="test_table.js"></script>
</body>
</html>
I tried to fix likely the same issue which caused by twitter bootstrap .modal-open class applied to body. The solution html {overflow-y: scroll} doesn't help. One possible solution I found is to add {width: 100%; width: 100vw} to the html element.
I use to have that problem, but the simples way to fix it is this (this works for me):
on the CSS file type:
body{overflow-y:scroll;}
as that simple! :)
The solutions posted using calc(100vw - 100%) are on the right track, but there is a problem with this: You'll forever have a margin to the left the size of the scrollbar, even if you resize the window so that the content fills up the entire viewport.
If you try to get around this with a media query you'll have an awkward snapping moment because the margin won't progressively get smaller as you resize the window.
Here's a solution that gets around that and AFAIK has no drawbacks:
Instead of using margin: auto to center your content, use this:
body {
margin-left: calc(50vw - 500px);
}
Replace 500px with half the max-width of your content (so in this example the content max-width is 1000px). The content will now stay centered and the margin will progressively decrease all the way until the content fills the viewport.
In order to stop the margin from going negative when the viewport is smaller than the max-width just add a media query like so:
#media screen and (max-width:1000px) {
body {
margin-left: 0;
}
}
Et voilà!
After trying most of the above CSS or JS-based solutions that haven't worked in my case, just wanted to add up to it.
My solution worked for the case where the scrollbar had to disappear on an event (e.g. a button click, cause you've just opened a full-screen menu that should block the page from being scrollable).
This should work when the below styles are applied to the element that turns overflow-y to hidden (in my case it's the body tag):
body {
overflow-x: hidden;
width: 100vw;
margin-right: calc(100vw - 100%);
}
Explanation: The width of your body tag is 100vw (so it includes the scrollbar's width).
By setting the margin-right, the margin only gets applied if your vertical scrollbar is visible (so your page content isn't actually under the scrollbar), meaning the page content will not reposition once overflow-y has changed.
Note: this solution only works for the pages that are not horizontally-scrollable.
Tested on Chrome 89.0, Firefox 87.0, Safari 14.0.3
Update: unfortunately it only works with centered container that doesn't take 100% width - otherwise the scrollbar overlays the piece of content on the right.
My approach is to make the track transparent. The scroll bar thumb color is #C1C1C1 to match the default scrollbar thumb color. You can make it anything you prefer :)
Try this:
html {
overflow-y: scroll;
}
body::-webkit-scrollbar {
width: 0.7em;
background-color: transparent;
}
body::-webkit-scrollbar-thumb {
background: #C1C1C1;
height:30px;
}
body::-webkit-scrollbar-track-piece
{
display:none;
}
I know the question is very old, but there is a new better method.
scrollbar-gutter: stable;
I tried overflow scroll but it didn't work for my case. the scroll bar still adds some kind of (white) padding. what works is changing the width from 100vw to 100%, but for the height it is ok to use 100vh. so this:
const Wrapper = styled.div`
min-height: 100vh
`
const Parent = styled.div`
width: 100%
`
const Children = styled.div`
width: 100%
`
Edit
I've set the width twice because the parent component held a sidebar, and the children. Depending on your use case, you can set it once.
Since I haven't found my solution here I would like to add it:
I did not want a permanent scrollbar (accepted solution) and I also decided to not use negative margins. They didn't (instantly) work for me in chrome and I also did not want to have content possibly disappearing below the scrollbar.
So this is a padding solution.
My web page consists of three parts:
Header (content is left aligned)
MainContent (content is centered)
Footer (content is left and right aligned)
Since the header would look bad with a left padding and since the logo should stay in the corner of the page, I kept it unchanged since the appearing of a scrollbar does not affect it in most cases (except when window width is very small).
Since an even padding is acceptable for both the MainContent and the footer I used only for those both containers the following css:
.main-content, .footer {
/*
* Set the padding to the maximum scrollbar width minus the actual scrollbar width.
* Maximum scrollbar width is 17px according to: https://codepen.io/sambible/post/browser-scrollbar-widths
*/
padding-right: calc(17px - (100vw - 100%));
padding-left: 17px;
}
This will keep the MainContent in the exact center and also work for all scrollbar width up to 17px. One could add a media query removing these paddings for mobile devices that have an overlay scrollbar.
This solution is similar to only adding the left padding and setting the width to "width: calc(100vw - 17px);". I cannot say if it would behave equally in all cases though.
I used some jquery to solve this
$('html').css({
'overflow-y': 'hidden'
});
$(document).ready(function(){
$(window).load(function() {
$('html').css({
'overflow-y': ''
});
});
});
#media screen and (min-width: 1024px){
body {
min-height: 700px
}
}
Contrary to the accepted answer which suggests a permanent scroll bar on the browser window even if the content doesn't overflow the screen, I would prefer using:
html{
height:101%;
}
This is because the appearance of scroll bar makes more sense if the content actually overflows.
This makes more sense than this.
I have a requirement to produce a HTML layout as follows:
The page should flow to occupy the available space in the browser window
It should have a fixed height header and footer
The central area should occupy the remaining height
The central area is broken into three columns. Each of these colums should be independently scrollable should the content exceed the available area.
I've had a go at this using a table of height 100% (works eventually with a bit of tweaking) with the top and bottom cells having fixed heights. This leaves the central area to occupy the remaining space. This area contains another table with three columns. Each cell contains a div with height and width set to 100% and overflow set to auto. It seems like it should work but excess content simply causes the main table to extend its height so that the whole page becomes scrollable.
Does anyone know of any examples of this working in practice? The solution is expected to be reasonably cross browser but doesn't have to cover every corner case.
Thanks,
Phil
Update
I figured out a solution and posted it as an answer here.
Note: I'm assuming HTML5 and CSS3 here, but kept to properties that work in most browsers. The HTML5 can easily be exchanged for HTML 4.01.
To create the kind of layout you want, we start with some basic HTML:
<div id="wrapper">
<header> Header </header>
<div id="content">
<section id="left"> Left </section>
<section id="center"> Center </section>
<section id="right"> Right </section>
</div>
<footer> Footer </footer>
</div>
The difficulty is styling this according to your needs. Starting out by setting a 100% height on as much as possible, along with suitable overflow values, we can obtain something very close to what you want:
html, body { height: 100%; margin: 0; padding: 0; }
#wrapper { height: 100%; }
header, footer { height: 50px; }
#content { height: 100%; overflow: hidden; }
section { float: left; overflow: auto; height: 100%; }
#left, #right { width: 100px; }
#center { width: 300px; }
Unfortunately, this makes the layout exactly 100px (the combined height of footer and header) too tall. To remedy this, we must decrease the height of #content by the same amount, but the standard box model doesn't allow for this. Enter the box-sizing (which is supported by all major browsers except IE7), which we can use to change the box model being used. With the border-box box model, padding is included in the height and as such we can "remove" the necessary height from #content:
#content { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; padding: 50px 0; margin: -50px 0; }
See also this JSfiddle demo and the full screen result for further details.
There are several examples of this type of layout available. One of the best is Matthew Levine's "Holy Grail," complete with tutorial.
You will note that this layout does not fix the footer at the bottom of the screen. You can do this by setting body (or an all-encompassing div) height to 100% and using overflow:hidden but this introduces potential usability issues. You may find that it is best to let your page expand to correct height as needed.
I figured out a solution, it's not elegant but it does work. I created a table set to 100% height. I then added a function which executes on load and resize. This gets the height of the window and subtracts from it, the height of the header and footer, it then sets the height of a div in the central area to be that remaining height. The main difficulty was coming up with an accurate window height, through various bits of googling, I came up with the following which appears to work fine:
function getWindowHeight() {
var height = 0;
var body = window.document.body;
if (window.innerHeight) {
height = window.innerHeight;
} else if (body.parentElement.clientHeight) {
height = body.parentElement.clientHeight;
} else if (body && body.clientHeight) {
height = body.clientHeight;
}
return height;
}
I have a website with center-aligned DIV. Now, some pages need scrolling, some don't. When I move from one type to another, the appearance of a scrollbar moves the page a few pixels to the side. Is there any way to avoid this without explicitly showing the scrollbars on each page?
overflow-y:scroll is correct, but you should use it with the html tag, not body or else you get a double scrollbar in IE 7
So the correct css would be:
html {
overflow-y: scroll;
}
Wrap the content of your scrollable element into a div and apply padding-left: calc(100vw - 100%);.
<body>
<div style="padding-left: calc(100vw - 100%);">
Some Content that is higher than the user's screen
</div>
</body>
The trick is that 100vw represents 100% of the viewport including the scrollbar. If you subtract 100%, which is the available space without the scrollbar, you end up with the width of the scrollbar or 0 if it is not present. Creating a padding of that width on the left will simulate a second scrollbar, shifting centered content back to the right.
Please note that this will only work if the scrollable element uses the page's entire width, but this should be no problem most of the time because there are only few other cases where you have centered scrollable content.
html {
overflow-x: hidden;
margin-right: calc(-1 * (100vw - 100%));
}
Example. Click "change min-height" button.
With calc(100vw - 100%) we can calculate the width of the scrollbar (and if it is not displayed, it will be 0). Idea: using negative margin-right, we can increase the width of <html> to this width. You will see a horizontal scroll bar — it should be hidden using overflow-x: hidden.
I think not. But styling body with overflow: scroll should do. You seem to know that, though.
With scroll always being shown, maybe be not good for layout.
Try to limit body width with css3
body {
width: calc(100vw - 34px);
}
vw is the width of the viewport (see this link for some explanation)
calc calculate in css3
34px stands for double scrollbar width (see this for fixed or this to calculate if you don't trust fixed sizes)
If changing size or after loading some data it is adding the scroll bar then you can try following, create class and apply this class.
.auto-scroll {
overflow-y: overlay;
overflow-x: overlay;
}
I don't know if this is an old post, but i had the same problem and if you want to scroll vertically only you should try overflow-y:scroll
body {
scrollbar-gutter: stable both-edges;
}
New css spec that will help with scrollbar repositioning is on its way:
https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-gutter
Summary
I see three ways - each with their own quirks:
scrollbar-gutter as mentioned by Markus T.
overflow: overlay as mentioned by kunalkamble
Add spacing with calc(100vw - 100%) as mentioned Rapti
Here is a StackBlitz demo
Press the "Toggle height" to see the content shift.
scrollbar-gutter
This has limited support but with a #support media query we can use a combination of this and overflow-y: scroll:
html {
overflow-y: scroll;
}
#supports (scrollbar-gutter: stable) {
html {
overflow-y: auto;
scrollbar-gutter: stable;
}
}
In this way content will never shift.
The "problem" with this solution is that there is always a fixed space for the scrollbar.
overflow: overlay
Limited support and it obviously hides anything it overlays. Special care is needed to make sure nothing vital is hidden (also on zoom and text size changes).
Can be combined with scrollbar-gutter:
html {
overflow-y: scroll;
}
#supports (scrollbar-gutter: stable) {
html {
overflow-y: auto;
scrollbar-gutter: stable;
}
}
#supports (overflow-y: overlay) {
html {
overflow-y: overlay;
scrollbar-gutter: auto;
}
}
It is possible to do some negative margin and overflow-x: hidden but this has a risk of hiding vital content under certain situations. Small screen, custom font/zoom size, browser extensions, etc.
calc(100vw - 100%)
This can be done with RTL support like this:
html[dir='ltr'] main {
padding-left: calc(100vw - 100%);
}
html[dir='rtl'] main {
padding-right: calc(100vw - 100%);
}
Where <main> in this case would be the container for the centered content.
Content here will not shift as long as the centered container is smaller than <main>. But as soon as it is 100% of the container a padding will be introduced. See the StackBlitz demo and click "Toggle width".
The "problem" with this solution is that you need media queries to prevent padding on "small screens" and that even on small screens - when the scrollbar should be visible - some shifting will occur because there is no room for 100% content and a scrollbar.
Conclusion
Use scrollbar-gutter perhaps combined with overlay. If you absolutely don't want empty spacing, try the calc solution with media queries.
Simply setting the width of your container element like this will do the trick
width: 100vw;
This will make that element ignore the scrollbar and it works with background color or images.
#kashesandr's solution worked for me but to hide horizontal scrollbar I added one more style for body. here is complete solution:
CSS
<style>
/* prevent layout shifting and hide horizontal scroll */
html {
width: 100vw;
}
body {
overflow-x: hidden;
}
</style>
JS
$(function(){
/**
* For multiple modals.
* Enables scrolling of 1st modal when 2nd modal is closed.
*/
$('.modal').on('hidden.bs.modal', function (event) {
if ($('.modal:visible').length) {
$('body').addClass('modal-open');
}
});
});
JS Only Solution (when 2nd modal opened from 1st modal):
/**
* For multiple modals.
* Enables scrolling of 1st modal when 2nd modal is closed.
*/
$('.modal').on('hidden.bs.modal', function (event) {
if ($('.modal:visible').length) {
$('body').addClass('modal-open');
$('body').css('padding-right', 17);
}
});
I've solved the issue on one of my websites by explicitly setting the width of the body in javascript by the viewport size minus the width of the scrollbar. I use a jQuery based function documented here to determine the width of the scrollbar.
<body id="bodyid>
var bodyid = document.getElementById('bodyid');
bodyid.style.width = window.innerWidth - scrollbarWidth() + "px";
Extending off of Rapti's answer, this should work just as well, but it adds more margin to the right side of the body and hides it with negative html margin, instead of adding extra padding that could potentially affect the page's layout. This way, nothing is changed on the actual page (in most cases), and the code is still functional.
html {
margin-right: calc(100% - 100vw);
}
body {
margin-right: calc(100vw - 100%);
}
Expanding on the answer using this:
body {
width: calc(100vw - 17px);
}
One commentor suggested adding left-padding as well to maintain the centering:
body {
padding-left: 17px;
width: calc(100vw - 17px);
}
But then things don't look correct if your content is wider than the viewport. To fix that, you can use media queries, like this:
#media screen and (min-width: 1058px) {
body {
padding-left: 17px;
width: calc(100vw - 17px);
}
}
Where the 1058px = content width + 17 * 2
This lets a horizontal scrollbar handle the x overflow and keeps the centered content centered when the viewport is wide enough to contain your fixed-width content
If the width of the table won't change, you can set the width of the element (such as tbody) that contains the scrollbar > 100% (allowing extra space for the scrollbar) and set overflow-y to "overlay" (so that the scrollbar stays fixed, and won't shift the table left when it appears). Also set a fixed height for the element with the scrollbar, so the scrollbar will appear once the height is exceeded. Like so:
tbody {
height: 100px;
overflow-y: overlay;
width: 105%
}
Note: you will have to manually adjust the width % as the % of space the scrollbar takes up will be relative to your table width (ie: smaller width of table, more % required to fit the scrollbar, as it's size in pixels is constant)
A dynamic table example:
function addRow(tableID)
{
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
var colCount = table.rows[0].cells.length;
for(var i=0; i<colCount; i++)
{
var newRow = row.insertCell(i);
newRow.innerHTML = table.rows[0].cells[i].innerHTML;
newRow.childNodes[0].value = "";
}
}
function deleteRow(row)
{
var table = document.getElementById("data");
var rowCount = table.rows.length;
var rowIndex = row.parentNode.parentNode.rowIndex;
document.getElementById("data").deleteRow(rowIndex);
}
.scroll-table {
border-collapse: collapse;
}
.scroll-table tbody {
display:block;
overflow-y:overlay;
height:60px;
width: 105%
}
.scroll-table tbody td {
color: #333;
padding: 10px;
text-shadow: 1px 1px 1px #fff;
}
.scroll-table thead tr {
display:block;
}
.scroll-table td {
border-top: thin solid;
border-bottom: thin solid;
}
.scroll-table td:first-child {
border-left: thin solid;
}
.scroll-table td:last-child {
border-right: thin solid;
}
.scroll-table tr:first-child {
display: none;
}
.delete_button {
background-color: red;
color: white;
}
.container {
display: inline-block;
}
body {
text-align: center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="test_table.css">
</head>
<body>
<h1>Dynamic Table</h1>
<div class="container">
<table id="data" class="scroll-table">
<tbody>
<tr>
<td><input type="text" /></td>
<td><input type="text" /></td>
<td><input type="button" class="delete_button" value="X" onclick="deleteRow(this)"></td>
</tr>
</tbody>
</table>
<input type="button" value="Add" onclick="addRow('data')" />
</div>
<script src="test_table.js"></script>
</body>
</html>
I tried to fix likely the same issue which caused by twitter bootstrap .modal-open class applied to body. The solution html {overflow-y: scroll} doesn't help. One possible solution I found is to add {width: 100%; width: 100vw} to the html element.
I use to have that problem, but the simples way to fix it is this (this works for me):
on the CSS file type:
body{overflow-y:scroll;}
as that simple! :)
The solutions posted using calc(100vw - 100%) are on the right track, but there is a problem with this: You'll forever have a margin to the left the size of the scrollbar, even if you resize the window so that the content fills up the entire viewport.
If you try to get around this with a media query you'll have an awkward snapping moment because the margin won't progressively get smaller as you resize the window.
Here's a solution that gets around that and AFAIK has no drawbacks:
Instead of using margin: auto to center your content, use this:
body {
margin-left: calc(50vw - 500px);
}
Replace 500px with half the max-width of your content (so in this example the content max-width is 1000px). The content will now stay centered and the margin will progressively decrease all the way until the content fills the viewport.
In order to stop the margin from going negative when the viewport is smaller than the max-width just add a media query like so:
#media screen and (max-width:1000px) {
body {
margin-left: 0;
}
}
Et voilà!
After trying most of the above CSS or JS-based solutions that haven't worked in my case, just wanted to add up to it.
My solution worked for the case where the scrollbar had to disappear on an event (e.g. a button click, cause you've just opened a full-screen menu that should block the page from being scrollable).
This should work when the below styles are applied to the element that turns overflow-y to hidden (in my case it's the body tag):
body {
overflow-x: hidden;
width: 100vw;
margin-right: calc(100vw - 100%);
}
Explanation: The width of your body tag is 100vw (so it includes the scrollbar's width).
By setting the margin-right, the margin only gets applied if your vertical scrollbar is visible (so your page content isn't actually under the scrollbar), meaning the page content will not reposition once overflow-y has changed.
Note: this solution only works for the pages that are not horizontally-scrollable.
Tested on Chrome 89.0, Firefox 87.0, Safari 14.0.3
Update: unfortunately it only works with centered container that doesn't take 100% width - otherwise the scrollbar overlays the piece of content on the right.
My approach is to make the track transparent. The scroll bar thumb color is #C1C1C1 to match the default scrollbar thumb color. You can make it anything you prefer :)
Try this:
html {
overflow-y: scroll;
}
body::-webkit-scrollbar {
width: 0.7em;
background-color: transparent;
}
body::-webkit-scrollbar-thumb {
background: #C1C1C1;
height:30px;
}
body::-webkit-scrollbar-track-piece
{
display:none;
}
I know the question is very old, but there is a new better method.
scrollbar-gutter: stable;
I tried overflow scroll but it didn't work for my case. the scroll bar still adds some kind of (white) padding. what works is changing the width from 100vw to 100%, but for the height it is ok to use 100vh. so this:
const Wrapper = styled.div`
min-height: 100vh
`
const Parent = styled.div`
width: 100%
`
const Children = styled.div`
width: 100%
`
Edit
I've set the width twice because the parent component held a sidebar, and the children. Depending on your use case, you can set it once.
Since I haven't found my solution here I would like to add it:
I did not want a permanent scrollbar (accepted solution) and I also decided to not use negative margins. They didn't (instantly) work for me in chrome and I also did not want to have content possibly disappearing below the scrollbar.
So this is a padding solution.
My web page consists of three parts:
Header (content is left aligned)
MainContent (content is centered)
Footer (content is left and right aligned)
Since the header would look bad with a left padding and since the logo should stay in the corner of the page, I kept it unchanged since the appearing of a scrollbar does not affect it in most cases (except when window width is very small).
Since an even padding is acceptable for both the MainContent and the footer I used only for those both containers the following css:
.main-content, .footer {
/*
* Set the padding to the maximum scrollbar width minus the actual scrollbar width.
* Maximum scrollbar width is 17px according to: https://codepen.io/sambible/post/browser-scrollbar-widths
*/
padding-right: calc(17px - (100vw - 100%));
padding-left: 17px;
}
This will keep the MainContent in the exact center and also work for all scrollbar width up to 17px. One could add a media query removing these paddings for mobile devices that have an overlay scrollbar.
This solution is similar to only adding the left padding and setting the width to "width: calc(100vw - 17px);". I cannot say if it would behave equally in all cases though.
I used some jquery to solve this
$('html').css({
'overflow-y': 'hidden'
});
$(document).ready(function(){
$(window).load(function() {
$('html').css({
'overflow-y': ''
});
});
});
#media screen and (min-width: 1024px){
body {
min-height: 700px
}
}
Contrary to the accepted answer which suggests a permanent scroll bar on the browser window even if the content doesn't overflow the screen, I would prefer using:
html{
height:101%;
}
This is because the appearance of scroll bar makes more sense if the content actually overflows.
This makes more sense than this.