Make flex item have 100% height and overflow: scroll [duplicate] - html

This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 5 years ago.
I want a flex item to take 100% of remaining height and display the overflow: scroll bar.
It looks like problem comes from my #userList which takes 100% of the window height and not taking the remaining space .
body {
display: flex;
flex-direction: column;
min-height: 100%;
margin:0px;
}
.wrapper {
display: block;
flex: 1 1 auto;
display: flex;
flex-direction: row; /
}
#chatContainer {
background: orange;
width: calc(100% - 350px);
display: flex;
flex-direction: column;
}
#tabs{
background-color: red;
flex: 1 1 0px;
display: flex;
}
#usersContainer {
flex: 1 1 0;
display:flex;
flex-direction:column;
}
#userListWrapper {
background-color:pink;
flex: 1 1 auto;
display:flex;
}
#userList {
-webkit-flex: 1 1 auto;
overflow: auto;
min-height: 0px;
height:100%;
}
.input {
background-color: #49FFFC;
}
<div class="wrapper">
<div id="chatContainer">
<div id="webcamContainer">webcam</div>
<div id="tabs">tabs here</div>
<div id="footer" style="background-color:#A0C8FF;height:50px">footer</div>
</div>
<div id="usersContainer" style="background-color:blue">
<div class="input">searchInput1</div>
<div class="input">searchInput2</div>
<div id="userList">
user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>
user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>
user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>
user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>
</div>
</div>
</div>
https://jsfiddle.net/jpo31gq9/

The main problem you are having is a violation of the rules governing percentage heights in CSS.
Basically, when using percentage heights, you must always specify the height of the parent element. Otherwise, the element with a percentage height has no frame of reference, and the height computes to auto (the height of the content).
From the spec:
CSS height property
percentage Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly and this element is not absolutely positioned, the value computes to "auto".
auto The height depends on the values of other properties.
source: https://www.w3.org/TR/CSS21/visudet.html#propdef-height
So if you plan to use percentage heights, you need to specify a height on every parent element up to the root element (html) or up to a fixed height declaration (such as height: 250px).
In your CSS, you have body { min-height: 100%; }. However, there is no height specified on the parent (html).
The following parent elements in your code are missing a height declaration:
html
body (min-height doesn't count)
.wrapper
#chatContainer
With the following adjustments your layout works.
html { height: 100%; } /* NEW */
body {
display: flex;
flex-direction: column;
/* min-height: 100%; */
margin: 0px;
height: 100%; /* NEW */
}
.wrapper {
display: block;
flex: 1 1 auto;
display: flex;
flex-direction: row;
height: 100%; /* NEW */
}
#chatContainer {
background: orange;
width: calc(100% - 350px);
display: flex;
flex-direction: column;
height: 100%; /* NEW */
}
Revised Fiddle
It's also worth mentioning some variations among current browsers.
Percentage Heights: Chrome/Safari vs Firefox/IE
Although the traditional implementation of percentage heights uses the value of the height property, recently some browsers have broadened their scope.
As evidenced in the following posts, Firefox and IE are now also using flex heights to resolve the percentage height of child elements.
Chrome / Safari not filling 100% height of flex parent
Height is not correct in flexbox items in Chrome
Flexbox in Chrome--How to limit size of nested elements?
Chrome ignoring flex-basis in column layout
Bottom line: Chrome and Safari resolve percentage heights based on the value of the parent's height property. Firefox and IE11/Edge use the parent's computed flex height.
For now, the simplest cross-browser solution to this problem would be, in my view, using the height property across the board for percentage heights.

Related

While using flex (column) for parent, Auto margin shrinks the child div [duplicate]

This question already has answers here:
How can I center text (horizontally and vertically) inside a div block?
(27 answers)
Closed 2 years ago.
I am trying to horizontally center one div inside parent div (Which is display flex in column mode) using margin 0 auto. When I do this the inner div is getting shrinked to the size of its content. Can someone explain why this is happening and how to fix this?
HTML
<div class="container">
<div class="mydiv">
CENTER THIS DIV
</div>
</div>
CSS
.container{
background-color: brown;
height: 100px;
display: flex;
flex-direction: column;
}
.mydiv{
background-color: chartreuse;
max-width: 500px;
margin: 0 auto;
}
If I remove flex from parent, then I am getting the correct output :
However, with the flex properties as in above code, this is what I get :
When you use display: flex; in a parent, the children automatically get the default flex values:
The item is sized according to its width and height properties. It shrinks to its minimum size to fit the container, but does not grow to absorb any extra free space in the flex container. This is equivalent to setting "flex: 0 1 auto".
That's why your .mydiv adjusts to fit the text.
(more info: https://developer.mozilla.org/en-US/docs/Web/CSS/flex)
If you don't want that to happen you could do something like this:
.container{
background-color: brown;
height: 100px;
display: flex;
flex-direction: column;
align-items: center; /* add this */
}
.mydiv{
background-color: chartreuse;
width: 100%; /* add this */
max-width: 500px; /* add this */
}
Working example:
https://codepen.io/sergiofruto/pen/dyMqbrm

Why's CSS percentage (%) height applied to grand-child of flex element?

I'm trying to check how CSS 100% height property works. But there's one thing I can't understand.
Why's 100% height working perfectly on .flex-grand-child (Chrome)? Does .flex-child have height property? So why it's even working???
Here's JSFiddle
html, body {
height: 100%;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
}
.flex-parent {
flex: 1 0 auto;
display: flex;
}
.flex-child {
width: 300px;
}
.flex-grand-child {
height: 100%;
background-color: green;
}
<div class="container">
<div class="flex-parent">
<div class="flex-child">
<div class='flex-grand-child'></div>
</div>
</div>
</div>
This is a particular case where the browser can handle percentage value on height due to the stretch effect of flexbox. The flex-child has a default alignment equal to stretch which is equivalent to having height:100% then the flex-parent is also filling its parent height with flex-grow:1. At the end, the browser was able to correctly resolve the height:100% of flex-grand-child
If the flex item has align-self: stretch, redo layout for its contents, treating this used size as its definite cross size so that percentage-sized children can be resolved.ref
If you disable the stretch alignment, it will break:
html,
body {
height: 100%;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
}
.flex-parent {
flex: 1 0 auto;
display: flex;
}
.flex-child {
width: 300px;
min-height: 200px;
align-self: flex-start; /*this will break it*/
border: 1px solid;
}
.flex-grand-child {
height: 100%;
background-color: green;
}
<div class="container">
<div class="flex-parent">
<div class="flex-child">
<div class='flex-grand-child'></div>
</div>
</div>
</div>
To use simple words: When having the stretch effect, the browser will first define the parent height based on its own parent (the content play no role here) then the browser will make the content height:100% of the previous calculated height. Without stretch the browser need to consider the content to define the height of the parent and here we will fall into the classic issue of percentage height.
Related question to get more cases where percentage can be resolved without having an explicit height defined on the parent element: Why is my Grid element's height not being calculated correctly?
Here is the relevant part of the specification dealing with this: https://www.w3.org/TR/css-sizing-3/#percentage-sizing
It's a bit complex but it's different from the CSS2 specification where percentage will always fail if the parent height is not specified:
If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to 'auto'.
The .flex-parent element has flex-grow: 1 applied, giving it the full height of the .container (height: 100%). It also has display: flex applied, making it a flex container.
This latter setting automatically triggers align-items: stretch, which causes the flex item – .flex-child – to expand the full height of the container. So the .flex-child computes to height: 100%.
Modern browsers, now accepting flex heights as a reference point for children with percentage heights, set the child of the flex item – .flex-grand-child – to the full height of the parent, which is height: 100%.
More details here: Chrome / Safari not filling 100% height of flex parent
You have .container as a flex container with a flex-direction of column, so by default, the child element will stretch to fill. So .flex-parent is stretching to fill .container.
Since .flex-parent is also a flex-container, .flex-child is stretching to fill that.
Finally, since .flex-grand-child has height 100%, it is also filling the entire area.

flex and overflow : weird behaviour [duplicate]

This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Closed 3 years ago.
EDIT: added flex-direction: column, missed it in the initial code.
When the child has overflow:auto and the parent has overflow:auto, the scrollbars appear on the child.
But when overflow:auto is removed from the parent, the scrollbars appear on the grand-parent .
html,
body {
height: 100%;
width: 100%;
overflow: hidden;
font-family: "Roboto", sans-serif;
}
body {
margin: 0;
padding: 0;
}
.App {
display: flex;
height: 100%;
}
.grand-parent {
display: flex;
flex-direction: column;
background: red;
overflow: auto;
padding: 20px;
}
.parent {
display: flex;
overflow: auto;
padding: 20px;
background: green;
}
.child {
overflow: auto;
font-size: 156px;
}
<div class="App">
<div class="grand-parent">
<div class="parent">
<div class="child">
Some content which grows bigger
</div>
</div>
</div>
</div>
Why is that? I would still expect the scrollbars to appear on the child.
How is the browser layout algorithm working here?
EDIT:
weirdly enough, the behavior seems to depend on the grand-parent having flex-direction: column. It works as I expect when flex-direction: row
tested on Chrome 75, firefox 67
This seems to have something to do with flex-direction on the grand-parent, if flex-direction is row, the horizontal scroll shows this behavior, if flex-direction is column, the vertical scroll shows this behavior
EDIT:
On further experiment, If we set min-height: 0 on parent, it behaves as expected, so this issue might be similar to
https://moduscreate.com/blog/how-to-fix-overflow-issues-in-css-flex-layouts/
https://css-tricks.com/flexbox-truncated-text/
For overflow-y, the CSS property which controls how content overflows parent vertical edges, the default value is visible. Here is how it works:
Content is not clipped and may be rendered outside the padding box's top and bottom edges.
This means that if the content doesn't fit in the box, some content will be rendered outside the box.
This property is not inherited, however. The CSS below will not set the overflow property to auto on children of div with ID parent:
var parentElem = document.getElementById('parent');
var childElem = document.getElementById('child');
console.log('overflow-y property of parent element: ' + window.getComputedStyle(parentElem).overflowY)
console.log('overflow-y property of child element: ' + window.getComputedStyle(childElem).overflowY)
#parent {
overflow: auto;
}
<div id="parent">
<div id="child">
Some content
</div>
</div>
This means that when content overflows in children boxes, scrollbars are automatically displayed by browsers on parent boxes; you will have to specify explicitly the property on children nodes as needed.

How to force a div to scroll after a certain size?

The Fiddle
This fiddle explains the problem clearly: fiddle (Edit: fixed broken fiddle.)
The Problem
I have a container div that has 3 divs inside of it.
The top div and middle div are dynamic in height. The bottom div is fixed.
Once the middle div expands enough, I want it to be scrollable.
Code Snippet
The basic structure:
<div id='container'>
<div id='top'>Top (dynamic) content</div>
<div id='middle'>Middle (dynamic) content</div>
<div id='bottom'>Bottom (fixed) content</div>
</div>
The basic CSS:
#container {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 250px;
padding-bottom: 100px; /* bottom div height */
}
#top {
???
}
#middle {
???
}
#bottom {
position: absolute;
bottom: 0;
left: 0;
height: 100px;
}
The Question
Is there a way to accomplish this using just CSS? (By just CSS, I mean no JavaScript.)
Here is an approach using flexboxes for the layout:
Example Here
Set the display of the parent #container element to flex. Since you want the element to stack vertically, set the flex-direction property's value to column. And justify-content: space-between is used to position the last element at the bottom when the height of the middle element decreases.
It's worth pointing out that vh units are used to set the height of the parent element to the height of the viewport.
#container {
height: 100vh;
display: flex;
flex-direction: column;
justify-content: space-between;
}
I also set the middles element's flex-shrink property to a relatively arbitrary number in order for it to shrink. Then flex-basis: 100% is used to force the element to fill the remaining space.
#middle {
overflow-y: auto;
flex-shrink: 50;
flex-basis: 100%;
}
Yes, set a max-height on the #container. You may also need to fiddle with the overflow property. Start by setting it to scroll.
You could do
#middle {
overflow-y: auto; /* does nothing */
height: calc(100% - 100px);
}

Set number of div elements' width based on static width container

I want to set the width of the div elements' width accordingly depending on their container width. However, the number will be changed, so the width will need to be adjusted accordingly. Here is a CSSDeck link to explain the situation clearly:
http://cssdeck.com/labs/hvmkapkd
As you can see, both containers are identical (needed), also they have modular content (<div> elements) (which is also needed). Keeping the same structure, is it possible to auto adjust the width of the divs using CSS so that they fill up the whole container?
Then each item in the first container would have 33.333% width, and each item in the second container would have 20% width.
I found the solution right after posting the question.
Setting the .container elements as table and setting the colored content as table-cell made it.
Link is updated above, but here is the link once again anyway:
http://cssdeck.com/labs/hvmkapkd
Give the flex-box concept a chance (https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes)
.container{
height: 100px;
width: 100px;
background-color: lightgray;
margin: 20px;
/* flexbox setup */
display: -webkit-flex;
-webkit-flex-direction: row;
display: flex;
flex-direction: row;
}
.container > div {
height: 100%;
/* flexbox setup */
-webkit-flex: 1 1 auto;
flex: 1 1 auto;
}
(http://cssdeck.com/labs/full/hvmkapkd)