I have a layout where I have a scrollable list of items in the center, with some stuff above and below it in a column. The list should take up as much empty space as is available to it in the column (I don't want to specify a specific height on it), and should scroll when the empty space in the column is not enough to fit all the items.
Here is a JSFiddle of the situation.
Notice that with just a few items in the scroller, it expands to fill the empty space in the column (as is intended). But then if you add several more items to the scroller, it expands to fit the entirety of its contents instead of staying at its original size, and then scrolling its overflowing contents; even though the it has overflow-y: scroll set!
However, if you then set the scroller to have a height of 0, the problem is fixed and the items scroll as is intended, with the scroller at its original height before the extra items were added.
But WHY!? Can someone please explain to me what's going on here? Also, is there any consequences of this "solution" that I'm not seeing?
<div class="column">
<div class="title">Header</div>
<div class="scroller">
<div class="item">Child</div>
<div class="item">Child</div>
</div>
<div class="title">Footer</div>
</div>
,
.column {
display: flex;
flex-direction: column;
height: 200px;
}
.title {
height: 50px;
flex-shrink: 0;
}
.scroller {
flex-grow: 20;
flex-shrink: 0;
overflow-y: scroll;
}
.item {
height: 20px;
margin-top: 2px;
}
Some quick background for anyone who runs across this later:
Elements that have flex-grow expand to take up x units of the available space minus the other flex content. In your case, .scroller is the only one with flex-grow but the other flex elements have defined heights so their content takes up space.
Elements that have flex-shrink contract as the space decreases. A zero value means they don't contract, a value >=1 allows scaling down.
However flex-shrink ONLY works if the element DOES NOT also have a flex-grow applied to it. Elements with both shrink & grow will only shrink to the size of their content
In your example, overflow doesn't kick in when the element is as big as the content (see above) which it is because you have both grow/shrink applied. Adding an explicit height (height: 0) overrides the computed "content" height allowing the flex-shrink to compress the element smaller than its content. This, in turn, makes the scrollbar work.
I don't know if this will cause any oddities at some point but it's an interesting solution to the problem and does seem to work pretty well.
You need to add a height to your scroller container css:
height: 30px;
Or max-height to allow growth to a limit:
max-height: 30px;
Either way, for the scroll to kick in, the container needs to feel constrained, so maybe:
height: 100%;
Then limit the size of its container.
I was able to get this working by setting flex-shrink on the scroller element to 1. It will cap out at its available space and use the scrollbar.
Related
I'm looking to create a div that only takes up as much width as it needs, with the height set to the height of the viewport. The problem I'm experiencing is that if the viewport height is reduced, the div's width doesn't update and the content overflows on the y-axis.
I've tried using flexbox to create two divs, one taking up the remaining room, but it doesn't force the other div to reduce in width so the words don't wrap.
Here's the first issue scenario:
Flexbox content not wrapping
In the image above, there are two div's using the following code:
.container {
display: flex;
}
.item-1 {
flex-grow: 0;
height: 100vh;
background-color:yellow;
}
.item-2 {
flex-grow: 1;
height: 100vh;
background-color:red;
}
The issue is that the text isn't wrapping to reduce the width of the first box to as little as possible. Here would be the desired result:
Desired flexbox content wrap
The second issue is that when the screen height is reduced, the content overflows instead of widening the div, as shown here:
Code overflowing outside of div
Ideally, these are the two desired results I am looking for:
Initial layout
(no overflow and as little width as possible)
Initial layout of desired result
Modified layout
(no overflow and the div width has widened to accommodate the content within it)
Modified layout of desired result
So far nothing I've tried has worked, am I asking for the impossible? I appreciate any help that can be provided.
I have an absolutely positioned element attached to the body of a page. It does not have limitations on its height or width. I have child of the absolute element that contains a list and it's height is limited on the y-axis. This listing can be variable in length and width so I would prefer not to use any hard-set paddings or margins nor "overflow-y: scroll" because the scroll bar will show even when not needed.
<style>
.the-absolute {
display: block;
position: absolute;
}
.the-list {
border: 1px solid blue;
display: flex;
flex-direction: column;
max-height: 100px; /* arbitrary limit for example */
overflow-y: auto;
white-space: nowrap;
}
</style>
<body>
<div class="the-absolute">
<div class="the-list">
<div>Title</div>
<div>Year</div>
<div>Studio</div>
<div>Worldwide</div>
<div>Domestic</div>
<div>Budget</div>
<div>Title</div>
<div>Year</div>
<div>Studio</div>
<div>Worldwide</div>
<div>Domestic</div>
<div>Budget</div>
</div>
</div>
</body>
I would expect the width of the child element to expand the parent width while accommodating the scroll bar. Instead, the content of the longest list items is overlapped by the scroll bar on the right.
This works as I would expect in Chrome, but does not seem to play nice in IE11 (surprise!), Firefox or Safari.
I am a bit baffled here and would appreciate a better understanding of how absolute positioning affects the children of an element and if there is a way I can have dynamic (i.e. no hard-set margins, widths, etc) list that will be scrollable if it hits a certain threshold without overlapping the content.
I have tried multiple iterations and wrapping elements but something about the absolute positioning causes this. I can hack it using JS but would prefer a pure CSS solution. I just assume there is some detail I am missing or I lack the right combination of keywords to find the solution via google/stackoverflow.
All help is appreciated!
Absolutely-positioned elements are no longer part of the document flow, so they aren't really "in" their parent element anymore. They therefore do not affect the parent's dimensions.
I'm currently trying to get an element (div) stretching itself over the free space of a parent element while respecting the size of other elements on its level. I found some solutions and tried most of them but I couldn't get it to work. I suspect this is because of the cms I'm working with which - when telling it to make a set of columns the same height - changes the parent display-style to table-cell. So... here is an image of what I'm trying to archive.
As said, the CMS changes the blue container to display: table-cell to stretch it over the whole area and make all columns in a row the same height. Inside of this blue container are the elements I can control. These are up to four div (white/green) inside of a parent div (yellow). The white div are dynamic and not always present and the green one needs to stretch over the whole vertical space no matter which of the white elements are present.
And idea how to accomplish that? I tried a lot of answers about this topic but they didnt work.. I think that's maybe due to the fact that the blue container is a table-cell?
edit: Here is what I got so far.
<div id="box_wrap">
<div class="box_title">
Title
</div>
<div class="box_image">
Image
</div>
<div class="box_content">
Content
</div>
<div class="box_more">
Read More
</div>
</div>
All of this is in a container provided by the CMS itself which has the attibute display: table-cell.
#box_wrap {
display: flex;
flex-direction: column;
}
.box_content {
display: flex;
flex: 2;
}
I think the problem might be that the container provided my the CMS has no defined height. If I give my #box_wrap a fixed height manually then the div in it will work as they should. I also tried height: auto and height: 100% for the #box_wrap and it doesn't work. Again, probably because the parent has no defined height, no? That is the last thing that I need to solve. The #box_wrap needs to stretch over the vertical, currently it only extends as far as it needs to cover the content.
I also noticed that the first image I provided wasn't 100% accurate so I updated it.
I would use this to allow the .box_content to grow (i.e. become higher) and the others not:
.box_title,
.box_image,
.box_image {
flex-grow: 0;
}
.box_content {
flex-grow: 1;
}
In addition, you should apply height: 100% to #box_wrap, but for that you also need height: 100% on body and html to have a reference for the height of #box_wrap. So, to sum up:
html, body {
height: 100%;
margin: 0;
}
#box_wrap {
height: 100%;
}
You also might want to add...
body {
padding: 10px;
box-sizing: border-box;
}
...to get that distance between the edge of the screen and your container as it's shown in your image.
This question already has answers here:
Can't scroll to top of flex item that is overflowing container
(12 answers)
Closed 6 years ago.
In this example, as soon as the browser window height drops below 400px, the image is no longer centered in the scrollable area.
html {
height: 100%;
}
body {
height: 100%;
display: flex;
align-items: center;
margin: 0;
padding: 0;
}
#content {
height: 400px;
display: flex;
align-items: center;
}
<div id="content">
<img src="http://placehold.it/300x300">
</div>
It works as soon as I unset the height property of the html or of the body or of both.
Still, I want to understand why centering in this specific example fails. Does it have something to do with the nested flexboxes? Or is there something problematic with setting the height of both, html and body, to 100%? Is it a bug or something browser related?
It's similar to margin: 0 auto (in conjunction with position: relative) for horizontal centering: As long as the container is wider than the centered child, the child will be centered. But as soon as the container (or the body/viewport) is narrower than the child, the child will be aligned left and a scrollbar will appear. That way it will always possible to see the whole child element - since it's larger than the container, that only is possible when scrolling is enabled.
In the situation you describe, the same happens with flexbox and vertical centering: If the parent container would be smaller (i.e. less high) than the child, and the child would be centered without a scrollbar, you wouldn't be able to see it's top and bottom part (which can be important for example if it's a form where you have to fill in text fields etc.), and you wouldn't be able to scroll to see those hidden parts. So in this situation (child higher than parent with child vertically centered in flex container), the child will be put at the top of the parent and you will be able to scroll down, which is good to either read/see the whole content or see/fill in the whole form in case of forms.
I have a dynamic-height container (its height is specified in relative measurements), inside of it, two elements - a header, and an img, e.g.:
<div class="item">
<header><h1>Title</h1></header>
<img ... />
</div>
I want the image to show in its entirety. Its css is set with height:100% .
Because of the height that the header takes, the image is clipped a little bit below (it is has an hidden overflown edge), where I want its height to auto adjust (become smaller) to fit inside the container.
There is a solution, where I use calc(100%-[height of header]) for the height of the image, but since calc is not supported in all browsers I was wondering if there is a different more supported solution for this.
Here is a jsfiddle:
http://jsfiddle.net/7xLo7mr6/
(Apply the class fix to the container to apply the calc fix)
Perhaps CSS flex could be your solution for this one:
http://jsfiddle.net/7xLo7mr6/9/
Using flex-direction: column; and applying a max-width to the container (allowing the image to fill in the rest of the height after the header text while not stretching the width) could potentially solve your issue, but might cause you more troubles depending on what you're ultimately after.
Another option: http://jsfiddle.net/7xLo7mr6/11/
apply height: 7%; to the header and height: 93%; to the image
Make the clipping happen at the top of the image instead of the bottom:
http://jsfiddle.net/7xLo7mr6/13/
Apply position: absolute; to the header, give it a background: white; and width: 100%;, then apply a position: relative; to the container so that the header applies a width 100% to the container and not the body.
If you just want the image to shrink when its container shrinks, you can give it a max-width of 100%, and that will stop your image from growing so large it exceeds its container.
.item img {
height: 100%;
max-width: 100%;
}
It might be important to note that declaring height: 100% does not make elements 100% of the height of their containers, it makes them 100% of their own intrinsic height. The heights of elements are determined by their content, not the other way around. Read a full explanation here: https://stackoverflow.com/a/5658062/4504641.
http://jsfiddle.net/ingridly/337wrgj8/1/