This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 5 years ago.
To better see the issue run below html code on firefox and on chrome and see the difference.
The code works on all browsers but not Chrome. The issue is when you set display to flex and flex-direction to column, and set one of the flex items flex-grow to 1. The content of this flex item can't have have height set to 100%.
Can you help me with work around without using JavaScript, or css Calc function?
Because in the actual project things are much more complex than this.
h1 {
margin: 0;
padding: 0;
color: white;
}
div {
font-size: 38px;
color: white;
}
<body style="margin: 0; padding: 0;">
<div style="height: 100vh; background: royalblue;">
<div style="display: flex; flex-direction: column; height: 100%;">
<div style="background: rosybrown; flex-grow: 0;">
This is first flex item
</div>
<div style="flex-grow: 1; background-color: red;">
<div style="background-color: orange; height: 100%;">
This div is inside flex item that grows to fill the remaining space. and has css height 100% but its not filling its parent.
<br/>this div need to be filling its parent (the red div). this works on all other browsers.
</div>
</div>
</div>
</div>
</body>
Add height: 100% to the parent of the orange div:
<div style="flex-grow: 1; background-color: red; height: 100%;"><!-- ADJUSTMENT HERE -->
<div style="background-color: orange; height: 100%;">
This div is inside flex item that grows to fill the remaining space.
and has css height 100% but its not filling its parent.
<br/>this div need to be filling its parent (the red div).
this works on all other browsers.
</div>
</div>
Essentially, 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 more details see bullet point #3 in this answer: https://stackoverflow.com/a/35051529/3597276
Related
How can I prevent a child div with scrollbars and flex:1 from exceeding the height of its parent flexbox in Firefox? It works correctly in Chrome.
CodePen link (if you prefer it to Stack Overflow snippets):
https://codepen.io/garyapps/pen/ZMNVJg
Details:
I have a flex container of fixed height. It has a flex-direction:column setting, and it contains multiple childen divs which will get vertically stacked. One of the child divs is given a flex:1 property, whereas others are given fixed heights.
My expectation is that the child div with the flex:1 property will expand to fill the remaining vertical space. This works as expected.
I have also given the child div an overflow-y:scroll property, so that if the content within it exceeds its height, scrollbars appear. This works fine in Chrome. In Firefox however, this child's height increases, exceeding its parent div.
In Chrome:
In Firefox:
As you see in the screenshot, I have two occurrences of this issue, once in the panel on the left, and the other in the panel on the right. In Chrome, the height of the child div remains constant, scrollbars appear, and the height of the parent does not get exceeded. In Firefox scrollbars do not appear, and the height of the child div increases and exceeds its parent.
I have looked at a few other similar questions on SO, and in many cases setting a min-height:0 property solved the problem in Firefox. However I have tried adding min-height:0 to parents, children, both parents and children, and had no luck.
Please run the code snippet below in both Chrome and Firefox to see the difference in the two browsers.
I would appreciate any advice on how to prevent child div from growing.
(Note that Bootstrap 4 is being used. The code snippet references the bootstrap 4 .css file CDN)
Code Snippet:
.body-content {
height: 300px;
max-height:100%;
border: 3px dashed purple;
display:flex;
flex-direction: column;
}
#messagescontainerrow {
flex: 1;
border: 5px double black;
}
#leftdiv {
display:flex;
flex-direction:column;
border: 1px solid green;
}
#messagetools {
height: 50px;
background-color: cornsilk;
}
#messagelist {
flex:1;
overflow-y: scroll;
background-color:whitesmoke;
}
#rightdiv {
display:flex;
flex-direction:column;
border: 1px solid blue;
}
#messagesenderspane {
width: 100%;
height: 50px;
background-color: lemonchiffon
}
#messagecontents {
flex: 1;
overflow-y: scroll;
width: 100%;
border: 1px solid blue;
background-color: aliceblue;
}
#messagesend {
width: 100%;
height: 70px;
background-color: whitesmoke;
}
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.2/css/bootstrap.min.css" rel="stylesheet"/>
</head>
<body>
<div class="container body-content">
<div class="row" id="messagescontainerrow">
<div class="col-5" id="leftdiv">
<div id="messagetools">
<input type="button" id="newbutton" value="My Button" />
</div>
<div id="messagelist">
<h4>Chat 1</h4>
<h4>Chat 2</h4>
<h4>Chat 3</h4>
<h4>Chat 4</h4>
<h4>Chat 5</h4>
<h4>Chat 6</h4>
<h4>Chat 7</h4>
<h4>Chat 8</h4>
</div>
</div>
<div class="col-7" id="rightdiv">
<div id="messagesenderspane">
Chat 3
</div>
<div id="messagecontents">
<h4>line 1</h4>
<h4>line 2</h4>
<h4>line 3</h4>
<h4>line 4</h4>
<h4>line 5</h4>
<h4>line 6</h4>
<h4>line 7</h4>
</div>
<div id="messagesend">
<textarea id="sendbox"></textarea>
<input type="button" id="sendbutton" value="Send" />
</div>
</div>
</div>
</div>
</body>
</html>
Short Answer
Instead of flex: 1, use flex: 1 1 1px.
Make these two adjustments in your code:
#messagelist {
/* flex:1; */
flex: 1 1 1px; /* new */
}
#messagecontents {
/* flex:1; */
flex: 1 1 1px; /* new */
}
revised codepen
Explanation
In most cases, as you have noted, adding min-height: 0 to flex items in a column-direction container is enough to correct the problem.
In this case, however, there's an additional obstacle: flex-basis.
You're applying the following rule to flex items #messagelist and #messagecontents: flex: 1.
This is a shorthand rule that breaks down to:
flex-grow: 1
flex-shrink: 1
flex-basis: 0
(source: https://www.w3.org/TR/css-flexbox-1/#flex-common)
2019 UPDATE: Since the posting of this answer in 2018, it appears that Chrome's behavior has changed and is now uniform with Firefox and Edge. Please keep that in mind as you read the rest of this answer.
In Chrome, flex-basis: 0 is enough to trigger an overflow, which generates the scrollbars. (2019 update: This may no longer be the case.)
In Firefox and Edge, however, a zero flex-basis is insufficient. This is probably the more correct behavior in terms of standards compliance as MDN states:
In order for overflow to have an effect, the block-level container must have either a set height (height or max-height) or white-space set to nowrap.
Well, flex-basis: 0 meets none of those conditions, so an overflow condition should not occur. Chrome has probably engaged in an intervention (as they often do).
An intervention is when a user agent decides to deviate slightly from a standardized behavior in order to provide a greatly enhanced user experience.
To meet the "standardized behavior", which would enable an overflow to occur in Firefox and Edge, give flex-basis a fixed height (even if it's just 1px).
I am marking Michael_B's answer as the correct one, since it is a valid solution along with an explanation. In addition here is another solution I came up with, which does not require modifying the flex-basis:
#messagescontainerrow {
flex: 1;
min-height: 0; /* ADDED THIS. */
border: 5px double black;
}
#leftdiv {
display:flex;
flex-direction:column;
max-height: 100%; /* ADDED THIS */
border: 1px solid green;
}
#rightdiv {
display:flex;
flex-direction:column;
max-height: 100%; /* ADDED THIS */
border: 1px solid blue;
}
Explanation:
As per the current Flexbox specification https://www.w3.org/TR/css-flexbox-1/#min-size-auto
In general, the automatic minimum size of a flex item is the smaller
of its content size and its specified size. However, if the box has an
aspect ratio and no specified size, its automatic minimum size is the
smaller of its content size and its transferred size. If the box has
neither a specified size nor an aspect ratio, its automatic minimum
size is the content size.
So, by default #messagescontainerrow was taking on a minimum height based on its contents, rather than respecting the height of its parent flexbox. This behavior can be overridden by setting min-height:0.
By making this change one sees what is displayed in the following image; note that #messagescontainerrow - the one with the double line border - is now the same height as its parent - the one with the purple dashed border.
(Note that the more recent draft specification, found here - https://drafts.csswg.org/css-flexbox/#min-size-auto - says "for scroll containers the automatic minimum size is zero". So in future we might not need to do this).
What remains now is the issue of its children, #leftdiv and #rightdiv, overflowing its borders. As Michael_B pointed out, overflow requires a height or max-height property to be present. So the next step is to add max-height: 100% to both #leftdiv and #rightdiv, so that the overflow-y:scroll property of their children gets triggered.
Here is the result:
How can I prevent a child div with scrollbars and flex:1 from exceeding the height of its parent flexbox in Firefox? It works correctly in Chrome.
CodePen link (if you prefer it to Stack Overflow snippets):
https://codepen.io/garyapps/pen/ZMNVJg
Details:
I have a flex container of fixed height. It has a flex-direction:column setting, and it contains multiple childen divs which will get vertically stacked. One of the child divs is given a flex:1 property, whereas others are given fixed heights.
My expectation is that the child div with the flex:1 property will expand to fill the remaining vertical space. This works as expected.
I have also given the child div an overflow-y:scroll property, so that if the content within it exceeds its height, scrollbars appear. This works fine in Chrome. In Firefox however, this child's height increases, exceeding its parent div.
In Chrome:
In Firefox:
As you see in the screenshot, I have two occurrences of this issue, once in the panel on the left, and the other in the panel on the right. In Chrome, the height of the child div remains constant, scrollbars appear, and the height of the parent does not get exceeded. In Firefox scrollbars do not appear, and the height of the child div increases and exceeds its parent.
I have looked at a few other similar questions on SO, and in many cases setting a min-height:0 property solved the problem in Firefox. However I have tried adding min-height:0 to parents, children, both parents and children, and had no luck.
Please run the code snippet below in both Chrome and Firefox to see the difference in the two browsers.
I would appreciate any advice on how to prevent child div from growing.
(Note that Bootstrap 4 is being used. The code snippet references the bootstrap 4 .css file CDN)
Code Snippet:
.body-content {
height: 300px;
max-height:100%;
border: 3px dashed purple;
display:flex;
flex-direction: column;
}
#messagescontainerrow {
flex: 1;
border: 5px double black;
}
#leftdiv {
display:flex;
flex-direction:column;
border: 1px solid green;
}
#messagetools {
height: 50px;
background-color: cornsilk;
}
#messagelist {
flex:1;
overflow-y: scroll;
background-color:whitesmoke;
}
#rightdiv {
display:flex;
flex-direction:column;
border: 1px solid blue;
}
#messagesenderspane {
width: 100%;
height: 50px;
background-color: lemonchiffon
}
#messagecontents {
flex: 1;
overflow-y: scroll;
width: 100%;
border: 1px solid blue;
background-color: aliceblue;
}
#messagesend {
width: 100%;
height: 70px;
background-color: whitesmoke;
}
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.2/css/bootstrap.min.css" rel="stylesheet"/>
</head>
<body>
<div class="container body-content">
<div class="row" id="messagescontainerrow">
<div class="col-5" id="leftdiv">
<div id="messagetools">
<input type="button" id="newbutton" value="My Button" />
</div>
<div id="messagelist">
<h4>Chat 1</h4>
<h4>Chat 2</h4>
<h4>Chat 3</h4>
<h4>Chat 4</h4>
<h4>Chat 5</h4>
<h4>Chat 6</h4>
<h4>Chat 7</h4>
<h4>Chat 8</h4>
</div>
</div>
<div class="col-7" id="rightdiv">
<div id="messagesenderspane">
Chat 3
</div>
<div id="messagecontents">
<h4>line 1</h4>
<h4>line 2</h4>
<h4>line 3</h4>
<h4>line 4</h4>
<h4>line 5</h4>
<h4>line 6</h4>
<h4>line 7</h4>
</div>
<div id="messagesend">
<textarea id="sendbox"></textarea>
<input type="button" id="sendbutton" value="Send" />
</div>
</div>
</div>
</div>
</body>
</html>
Short Answer
Instead of flex: 1, use flex: 1 1 1px.
Make these two adjustments in your code:
#messagelist {
/* flex:1; */
flex: 1 1 1px; /* new */
}
#messagecontents {
/* flex:1; */
flex: 1 1 1px; /* new */
}
revised codepen
Explanation
In most cases, as you have noted, adding min-height: 0 to flex items in a column-direction container is enough to correct the problem.
In this case, however, there's an additional obstacle: flex-basis.
You're applying the following rule to flex items #messagelist and #messagecontents: flex: 1.
This is a shorthand rule that breaks down to:
flex-grow: 1
flex-shrink: 1
flex-basis: 0
(source: https://www.w3.org/TR/css-flexbox-1/#flex-common)
2019 UPDATE: Since the posting of this answer in 2018, it appears that Chrome's behavior has changed and is now uniform with Firefox and Edge. Please keep that in mind as you read the rest of this answer.
In Chrome, flex-basis: 0 is enough to trigger an overflow, which generates the scrollbars. (2019 update: This may no longer be the case.)
In Firefox and Edge, however, a zero flex-basis is insufficient. This is probably the more correct behavior in terms of standards compliance as MDN states:
In order for overflow to have an effect, the block-level container must have either a set height (height or max-height) or white-space set to nowrap.
Well, flex-basis: 0 meets none of those conditions, so an overflow condition should not occur. Chrome has probably engaged in an intervention (as they often do).
An intervention is when a user agent decides to deviate slightly from a standardized behavior in order to provide a greatly enhanced user experience.
To meet the "standardized behavior", which would enable an overflow to occur in Firefox and Edge, give flex-basis a fixed height (even if it's just 1px).
I am marking Michael_B's answer as the correct one, since it is a valid solution along with an explanation. In addition here is another solution I came up with, which does not require modifying the flex-basis:
#messagescontainerrow {
flex: 1;
min-height: 0; /* ADDED THIS. */
border: 5px double black;
}
#leftdiv {
display:flex;
flex-direction:column;
max-height: 100%; /* ADDED THIS */
border: 1px solid green;
}
#rightdiv {
display:flex;
flex-direction:column;
max-height: 100%; /* ADDED THIS */
border: 1px solid blue;
}
Explanation:
As per the current Flexbox specification https://www.w3.org/TR/css-flexbox-1/#min-size-auto
In general, the automatic minimum size of a flex item is the smaller
of its content size and its specified size. However, if the box has an
aspect ratio and no specified size, its automatic minimum size is the
smaller of its content size and its transferred size. If the box has
neither a specified size nor an aspect ratio, its automatic minimum
size is the content size.
So, by default #messagescontainerrow was taking on a minimum height based on its contents, rather than respecting the height of its parent flexbox. This behavior can be overridden by setting min-height:0.
By making this change one sees what is displayed in the following image; note that #messagescontainerrow - the one with the double line border - is now the same height as its parent - the one with the purple dashed border.
(Note that the more recent draft specification, found here - https://drafts.csswg.org/css-flexbox/#min-size-auto - says "for scroll containers the automatic minimum size is zero". So in future we might not need to do this).
What remains now is the issue of its children, #leftdiv and #rightdiv, overflowing its borders. As Michael_B pointed out, overflow requires a height or max-height property to be present. So the next step is to add max-height: 100% to both #leftdiv and #rightdiv, so that the overflow-y:scroll property of their children gets triggered.
Here is the result:
I've got a container div with some padding around its content, a max height with overflow: auto, and some buttons at the bottom of the container. When the contents of the container grow enough so that a scrollbar appears, the bottom padding just disappears. This happens in seemingly every browser but Chrome.
.container {
border: 1px solid;
padding: 15px;
max-height: 200px;
overflow-y: auto;
display: inline-block;
width: 200px;
}
.footer {
background: green;
}
<div class="container">
<div style="height: 100px">Hello World</div>
<div class="footer">Footer Stuff</div>
</div>
<div class="container">
<div style="height: 200px">Hello World</div>
<div class="footer">Footer Stuff</div>
</div>
Here's what it looks like in Firefox. The right container is scrolled all the way down; you can see the lack of bottom padding.
Is this a known bug? Is there a recommended workaround?
(for the time being I'm going to make an "inner-container" class and put the padding on that instead of the outer "container", but it seems like I shouldn't need to do that)
I'm looking for the simplest way to achieve a type of layout that looks simple:
...but actually involves a lot of criteria, many of which involve non-trivial CSS issues:
Vertically centred content in a div...
...where the content is of variable length (so distance from top and bottom can't be hard coded)...
...where the div is inside a selection of floated divs...
...where those divs have percentage widths to fill the screen on a responsive layout...
...where there is a fixed pixel gap between each div...
...where the divs have solid background colours or images and the background behind the divs isn't a known solid colour that can be re-applied
Various elements of this have been addressed in separate questions (for example vertically aligning floated divs, and pixel gaps between responsive percentage-width divs), but I couldn't find anything combining them.
Simplest means:
As few HTML wrappers as possible
Minimal extra Javascript (none if possible)
Minimal CSS that needs to change when breakpoints change the number of divs on each row
Minimal code, quirks, or fragile CSS trickery (e.g. relying on browser quirks that could change in future)
Minimal cross browser issues (ideally, should work on IE8+ with minimal IE-specific markup)
Here's the simplest I can come up with. Code snippet below. It's basically an existing method for vertically centring floats, putting the background on the middle wrapper, and setting fixed pixel gaps using padding on the outer wrapper rather than margins with box-sizing: border-box;.
JSBIN demo
Three HTML elements per block - which seems to be the minimum for any floated vertically centred content where the inner content doesn't have a known height.
No JS
Only the % width needs to change to change the number of blocks per line
If the text content is too big for the div, the div expands slightly without breaking the layout - overflow: hidden; can be applied if this is undesirable
Works on IE8 with no issues (fails on IE7 if any poor souls still need to support IE7)
.box-outer {
box-sizing: border-box;
float: left;
/* editable */
width: 50%;
height: 110px;
padding: 1px 1px 0px 0px; /* sets gap */
/* Padding does't collapse like margins - 1px all round gives 2px gaps */
}
.box {
width: 100%;
height: 100%;
box-sizing: border-box;
display: table; /* height doesn't fill without display: table */
/* editable: */
background: #99ffff;
padding: 8px;
}
.box-inner {
vertical-align: middle;
display: table-cell;
}
.boxes-container {
padding: 0px 0px 1px 1px; /* opposite of each box's padding */
/* editable: */
background: #ffffff url('http://freedesignfile.com/upload/2012/10/sky_clouds_03.jpg');
}
<div class="boxes-container clearfix">
<h2> Title </h2>
<div class="box-outer">
<div class="box">
<div class="box-inner">
Box content
</div>
</div>
</div>
<div class="box-outer">
<div class="box">
<div class="box-inner">
Box with longer content
</div>
</div>
</div>
<div class="box-outer">
<div class="box">
<div class="box-inner">
Box
</div>
</div>
</div>
<div class="box-outer">
<div class="box">
<div class="box-inner">
Box with significantly longer textual content
</div>
</div>
</div>
<br/>
<p style="text-align: center;"> <--- responsive width ---> </p>
</div>
I recently decided to ditch tables and go with a div solution on this new project, however I'm having a really weird issue when setting a div within another div to 100% without it causing overflow equal to the height of the div's above it. It's acting like the browser isn't aware of the div's above it occupying that space.
I have a wrapper div with a fixed width and height set to 100%, within that is 3 column divs (left, mid and right) in the mid column I have 3 div's, the top 2 have fixed heights 90px and the 3rd is set to 100% to fill the rest of the content area but it's breaking out of the wrapper div and causing exactly 180px overflow. I setup this simple layout on JSFiddle: Height: 100% Div Issue
<body>
<div class="wrapper">
<div class="left">
<div style="background-color:fuchsia; height: 90px;"> </div>
</div>
<div class="mid">
<div style="background-color:purple; height: 90px; width: 998px;"> </div>
<div style="background-color:blue; height: 90px; width: 998px;"> </div>
<div style="background-color:black; height: 100%; width: 50%;"> </div>
</div>
<div class="right">
<div style="background-color:fuchsia; height: 90px;" class="right"> </div>
</div>
</div>
You will notice the black div is breaking out of the yellow (mid) div, this should not happen! Any help would be greatly appreciated. Thanks!
You're specifying a height of 100% on the black div, which ends up being relative to its parent (.mid) which also happens to contain the other elements that you gave 90px of height to. You have to account for those two siblings.
You can do this by using the calc() notation, though mobile browser support is bad and the function isn't supported in IE8 & below.
http://jsfiddle.net/KtUgF/5/
You can also use a negative top-margin on the black div equal to the sum of both of its siblings (180px):
http://jsfiddle.net/yrfnc/
This should fix the issue
height: 100vh;
Any reason why you can't just add overflow: hidden to the ".mid" div?
<div class="mid" style="overflow:hidden">
or
.mid {
float: left;
width: 998px;
height: 100%;
background-color: yellow;
overflow: hidden;
}