Fiddle: https://jsfiddle.net/Alexander6RI/vpeasg1t/
I have an image which resizes to fill the height of its parent div, and the parent div has its width set to min-content. This works as expected.
When a horizontal scrollbar is added, the image correctly resizes to keep its aspect ratio while filling the available height. The problem is, the parent div continues to behave as if the image were full size which creates an empty space to the right. The intended function would be for the div to become narrower, because it has width: min-content, but it doesn't.
Is this an intended feature to improve document flow? Is there a way to make it follow the expected behavior?
The width is fine, it works as it should. The problem is the height, the height of the horizontal scroll bar is taken from the height: 50vmin; so the new height of the but the image tries to maintain its aspect ratio so it gets squashed down. Even though the height changes, (because again, the height of the horizontal scroll bar takes up some part of the parent's height.) the viewport doesn't so the height stays constant.
.parent {
outline: 2px solid black;
width: min-content;
resize: vertical;
overflow-y: auto;
}
.child {
outline: 2px solid red;
height: 100%;
width: auto;
display: block;
}
But if you need the height you might need to set the height of the parent and the child to be the same value then set the overflow to hidden like so
.parent {
outline: 2px solid black;
width: min-content;
resize: vertical;
height: 50vmin;
overflow:hidden;
}
.child {
outline: 2px solid red;
height: 50vmin;
width: auto;
display: block;
}
A fraction of the image gets clipped at the bottom but that's the best solution I can think of.
You can probably use the object-fit css property like this:
.parent {
outline: 2px solid black;
width: min-content;
height: 50vmin;
resize: vertical;
overflow-y: auto;
}
.child {
outline: 2px solid red;
height: 100%;
object-fit: cover;
display: block;
}
With cover value you can maintain the aspect ratio using all of image's parent space (the image will be adapted to the new space).
I'm trying to mimic the behavior of overflow-y:hidden to overflow-x, but it doesn't behave the same way. overflow-x:hidden doesn't allow to scroll (by dragging the mouse).
See: http://jsfiddle.net/Gxm2z/
#container {
width: 300px
}
#modules {
height: 50px;
padding: 5px;
white-space: nowrap;
overflow-y: hidden;
overflow-x: scroll;
-webkit-overflow-scrolling: touch;
}
.module {
display: inline-block;
width: 50px;
height: 50px;
line-height: 50px;
text-align: center;
background: #ddd;
}
How can I achieve the same result without a scroll bar? I'm ok with a javascript/jQuery plugin.
The plan is to use arrows, and maybe a custom scrollbar
this is my solution CSS based - simple and nice on all devices, no need for additional JS.
add fixed height and overflow hidden to parent element (in your case #container)
enlarge height of #modules - this create enough place hidden under parent element for scrollbar (because of smaller #container height, this place is invisible)
using -webkit-overflow-scrolling:touch; is good choice, make nice behavior on iPad and iPhone
#container {
width: 300px;
height: 60px;
overflow: hidden;
}
#modules {
height: 90px; /* 40px - more place for scrollbar, is hidden under parent box */
padding: 5px;
white-space: nowrap;
overflow-x: scroll;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
}
live demo: http://jsfiddle.net/s6wcudua/
#modules {
height: 50px;
padding: 5px;
white-space: nowrap;
overflow-y: hidden;
overflow-x: scroll;
-webkit-overflow-scrolling: touch;
&::-webkit-scrollbar {
display: none;
}
}
This only work in webkit based browsers.
You could try using the ::-webkit-scrollbar pseudo element, like shown here.
http://iscrolljs.com/
Best Javascript custom scrollbar available, in my opinion. It will work great in Mobile, IE9+ and modern browsers. Plenty of options and callbacks. And yes, you can disable the visible scrollbar, but still retain horizontal scrolling.
I've got a list with certain height, and need to make it scroll to show the rest vertically.
So I added overflow-y: hidden; to the list.
But the submenu can't be visible, and a horizontal scrollbar showed.
Is there any solution?
code here
Simply increase the width of the .wrapper
.wrapper {
margin: 20px;
background: gray;
color: white;
width: 400px;
height: 100px;
/* I need overflow-y auto,but I also need to display the submenu*/
overflow-y: auto;
overflow-x: visible;
}
I can’t get padding-bottom to work when I use overflow-y: auto on a box. I use Firefox.
#container {
padding: 3em;
overflow-x: hidden;
overflow-y: auto;
width: 300px;
height: 300px;
background: red;
}
#some_info {
height: 900px;
background: #000;
}
<div id="container">
<div id="some_info"></div>
</div>
See the JSFiddle.
One more solution without extra DIVs.
#container:after {
content: "";
display: block;
height: 50px;
width: 100%;
}
Working in FF, Chrome, IE8-10.
I'm late to the party, but I thought it was worth adding a different solution that addresses some of the concerns raised above.
I came here because of exactly the kind of situation that #Philip raised in response to Alexandre Lavoie's solution: I have dynamically generated content inside the container, so I can't just apply styling to a specific div name like #some_info.
Happily, there's a simple solution for browsers that support CSS3: instead of applying bottom padding to the container, apply a bottom margin to the last child element inside the container.
#container > :last-child {
margin-bottom: 3em;
}
As long as the last child element in the container div is a block-level element, this should do the trick.
DEMO: http://jsfiddle.net/rwgZu/240/
P.S. If Firefox's failure to scroll to the bottom of the padding is indeed a bug (as suggested by #Kyle), it still hasn't been fixed as of Firefox 47.0. Frustrating! Internet Explorer 11.0.9600.17843 exhibits the same behavior. (Google Chrome, in contrast, shows the bottom padding as expected.)
The solutions above were not working for my needs, and I think I stumbled on a simple solution.
If your container and overflowing content share the same background color, you can add a top and bottom border with the color matching the background color. To create equal padding all around, set the border width equal to the left and right padding of the container.
Link to modified version of OP's fiddle: http://jsfiddle.net/dennisoneil/rwgZu/508/
A simple example below.
Note: Stack Overflow puts the snippet results into an overflow scroll, which makes it a little harder to see what's going on. The fiddle may be your best preview option.
#container {
background: #ccc;
overflow-y: scroll;
height: 190px;
padding: 0 20px;
border-top: 20px solid #ccc;
border-bottom: 20px solid #ccc;
}
#overflowing {
background: #ccc;
}
<div id="container">
<div id="overflowing">
This is content<br/>
This is content<br/>
This is content<br/>
This is content<br/>
This is content<br/>
This is content<br/>
This is content<br/>
This is content<br/>
This is content<br/>
This is content<br/>
This is content<br/>
This is content<br/>
This is content<br/>
This is content<br/>
This is content<br/>
</div>
</div>
Here is a possible approach that is working perfectly :
#container {
overflow-x: hidden;
overflow-y: auto;
width: 300px;
height: 300px;
}
#some_info {
height: 900px;
background: #000;
border: 3em solid red;
}
Style the parent div normally and make the inner div do what you want it to do.
Remove overflow-x and overflow on #container, change height to 100% and add overflow-y:scroll; on #some_info
#container {
padding: 3em;
width: 300px;
height: 300px;
background: red;
}
#some_info {
height: 100%;
background: #000;
overflow-y:scroll;
width:100%;
}
Working Demo: http://jsfiddle.net/9yuohxuh/
For those who are looking for a simple solution and can change the DOM, put the overflow on the outer element and the padding on the inner element.
.scroll {
overflow-x: hidden;
overflow-y: auto;
}
.scroll__inner {
padding: 3em;
}
In the example from the original question, it would look like this:
#container {
overflow-x: hidden;
overflow-y: auto;
width: 300px;
height: 300px;
background: red;
}
#some_info {
height: 900px;
background: #000;
padding: 3em;
box-sizing: border-box; /* only needed if wanting padding to not be added to height */
}
Note the use of box-sizing: border-box here, which is only needed as the OP has a hardcoded height (generally bad practice but could be needed in edge cases), so adding this border-box enables the 3em padding to not increase the height, but pad inside the 900px.
A final note, I'd advise avoiding ID's for styling, mostly due to their extremely high specificity, see this post for more info on that.
Demo
Hi now used to this css
#container {
padding: 3em;
overflow-x: hidden;
overflow-y: auto;
width: 300px;
height: 300px;
background: red;
padding-bottom:0; // add this line in your css
}
#some_info {
height: 900px;
background: #000;
margin-bottom:3em; // add this line in your css
}
Demo
It's not only with bottom padding. Right padding/border/spacing is also ignored (you can't see it in your example because it has no content, and the width is not scrolling)
All the answers above fail in chrome 43, generating up to 3 scrollbars! or if the content overflows #some_info.
Example: http://jsfiddle.net/LwujL3ad/
If it worked for you, it's probably because the content was not as wide as the scrolling element, or fixed sized.
The right solution is:
Set #some info to display:table, and add padding or border to it, not to the scrolling container.
#container {
overflow: scroll;
width: 300px;
height: 300px;
background: red;
padding-bottom:0;
}
#some_info {
display:table;
border: solid 3em red;
height: 900px;
background: #000;
margin-bottom:3em;
color: white;
}
DEMO: http://jsfiddle.net/juh7802x/
The only element that doesn't fail, and respects ANY border and padding you add in there as separator is a TABLE.
I tried, and no matter if it's the next direct child or it's nested many items deep, any non-content styling will NOT expand to wrap the content, and will stay 100% width of the parent. Which is nonsense, because having content BIGGER than the parent is EXACTLY the scenario in which a scrolling div is required!
For a dynamic solution (both the container and the content) set the container of the elements inside the scrolling container to display:table.
Based on isHristov's answer:
#container {
padding: 3em 3em 0 3em; /* padding-bottom: 0 */
overflow-x: hidden;
overflow-y: auto;
width: 300px;
height: 300px;
background: red;
}
#container:after {
content: "";
display: block;
height: 0;
width: 100%;
margin-bottom: 3em; /* length you wanted on padding-bottom */
}
However, his solution adds extra space in browsers that handle this situation properly.
Dan Robinson's answer is great too unless you have multiple elements, in #container, that are dynamically shown/hidden. In that case :last-child might target a hidden element and have no effect.
You just need to add box-sizing: border-box to the same element where you applied the overflow rule.
I think #-moz-document url-prefix() is what you need.
#container {
padding: 3em;
overflow-x: hidden;
overflow-y: auto;
width: 300px;
height: 300px;
background: red;
}
#some_info {
height: 900px;
background: #000;
}
#-moz-document url-prefix() {
#container > :last-child {
margin-bottom: 3em;
}
}
<div id="container">
<div id="some_info"></div>
</div>
The top answers did not work in FireFox 89. The only sensible solution I could think of is to use a div containing only a non-breaking space and with a fixed height set.
HTML
<div className="spacer"> </div>
CSS
.spacer {
height: 30px;
}
This works as it does not utilize margin or padding.
I have just faced this issue, it persists even in Firefox 87, version being released in 2021.
But it is finally fixed very recently. After update to Firefox 93 bottom padding with scroll works normally.
I have a container div which has children anchored to the bottom. The problem is that when the div's overflow scrollbar appears, the bottom margin of the last child gets hidden.
Please see http://jsfiddle.net/TxEAP/3/. At first, there's a correct margin underneath the 1 div. Clicking "append one" so that the scrollbar eventually appears makes the last div not have a bottom margin anymore. Opening DevTools shows that the margin of that last child is there, but it is outside of the container's viewport, even when scrolling completely to the bottom.
How can this be solved? It would suffice to get this working in Google Chrome.
HTML:
<div class="main">
<div class="container">
<div class="item">1</div>
<!-- several of these .item divs -->
</div>
</div>
CSS:
.main {
height: 200px;
overflow-y: scroll;
position: relative;
border: 1px solid black;
}
.container {
width: 100%;
max-height: 100%;
position: absolute;
bottom: 0;
}
.item {
padding: 20px;
margin: 15px;
border: 1px solid black;
}
Here's my final solution using flexbox. It's supported well enough on Chrome despite all -webkit- prefixes. Basically, the idea is to have a dummy element that, in case of no overflow, fills up the space of the container starting from the top (so that the real children are anchored to the bottom); in case of overflow, it is hidden automatically because of height: 0. It does not suffer from the margin issue, and it does not collapse margins.
http://jsfiddle.net/mCYLm/1/
HTML:
<div class="main">
<div class="gap-filler"></div>
<div class="item">foo</div>
<!-- more `div.item`s -->
</div>
CSS:
div.main {
display: -webkit-box;
-webkit-box-orient: vertical;
height: 200px;
overflow-y: scroll;
}
div.main div.gap-filler {
-webkit-box-flex: 1;
height: 0;
}
div.main div.item {
border: 1px solid black;
margin: 20px;
padding: 20px;
}
Edit: This was a solution without flexbox, but it had selection issues.
A solution that eventually worked was the following: http://jsfiddle.net/TxEAP/7/. This appends hidden "content" which makes Chrome not hide the margin of the last .item div.
.container:after {
content: "";
font-size: 0;
display: block;
height: 1px;
}
Edit: The following only works if display: inline-block is possible.
Finally I found a solution. If all .items have display: inline-block except the first one, then the margin does not get hidden.
http://jsfiddle.net/TxEAP/5/
.item:not(:first-child) {
display: inline-block;
/* attempt at getting `width: auto` like `display: block` has */
width: -webkit-calc(100% - 2 * 15px);
box-sizing: border-box;
}
If you just move the overflow-y: scroll; from .main. to .container class then the margin is preserved. The only drawback is for less than 3 items (for the given container height) you get a small scrollbar placeholder, instead of a full height one.
Removing max-height:100% on the container seems to fix it for my test in Chrome 21.
Moving the properties so that the overflow is on the container, preserves the margin/padding for an element added to the end that results in the scrollbar appearing.
.main {
height: 200px;
border: 1px solid black;
}
.container {
width: 100%;
height: 100%;
overflow-y: scroll;
}