Chrome / Safari not filling 100% height of flex parent
Solution 1
Solution
Use nested flex containers.
Get rid of percentage heights. Get rid of table properties. Get rid of vertical-align
. Avoid absolute positioning. Just stick with flexbox all the way through.
Apply display: flex
to the flex item (.item
), making it a flex container. This automatically sets align-items: stretch
, which tells the child (.item-inner
) to expand the full height of the parent.
Important: Remove specified heights from flex items for this method to work. If a child has a height specified (e.g. height: 100%
), then it will ignore the align-items: stretch
coming from the parent. For the stretch
default to work, the child's height must compute to auto
(full explanation).
Try this (no changes to HTML):
.container {
display: flex;
flex-direction: column;
height: 20em;
border: 5px solid black
}
.item {
display: flex; /* new; nested flex container */
flex: 1;
border-bottom: 1px solid white;
}
.item-inner {
display: flex; /* new; nested flex container */
flex: 1; /* new */
/* height: 100%; <-- remove; unnecessary */
/* width: 100%; <-- remove; unnecessary */
/* display: table; <-- remove; unnecessary */
}
a {
display: flex; /* new; nested flex container */
flex: 1; /* new */
align-items: center; /* new; vertically center text */
background: orange;
/* display: table-cell; <-- remove; unnecessary */
/* vertical-align: middle; <-- remove; unnecessary */
}
<div class="container">
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
</div>
Explanation
My problem is that
.item-inner { height: 100% }
is not working in webkit (Chrome).
It's not working because you're using percentage height in a way that doesn't conform with the traditional implementation of the spec.
10.5 Content height: the
height
propertypercentage
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 toauto
.auto
The height depends on the values of other properties.
In other words, for percentage height to work on an in-flow child, the parent must have a set height.
In your code, the top-level container has a defined height: .container { height: 20em; }
The third-level container has a defined height: .item-inner { height: 100%; }
But between them, the second-level container – .item
– does not have a defined height. Webkit sees that as a missing link.
.item-inner
is telling Chrome: give me height: 100%
. Chrome looks to the parent (.item
) for reference and responds: 100% of what? I don't see anything (ignoring the flex: 1
rule that is there). As a result, it applies height: auto
(content height), in accordance with the spec.
Firefox, on the other hand, now accepts a parent's flex height as a reference for the child's percentage height. IE11 and Edge accept flex heights, as well.
Also, Chrome will accept flex-grow
as an adequate parent reference if used in conjunction with flex-basis
(any numerical value works (auto
won't), including flex-basis: 0
). As of this writing, however, this solution fails in Safari.
#outer {
display: flex;
flex-direction: column;
height: 300px;
background-color: white;
border: 1px solid red;
}
#middle {
flex-grow: 1;
flex-basis: 1px;
background-color: yellow;
}
#inner {
height: 100%;
background-color: lightgreen;
}
<div id="outer">
<div id="middle">
<div id="inner">
INNER
</div>
</div>
</div>
Four Solutions
1. Specify a height on all parent elements
A reliable cross-browser solution is to specify a height on all parent elements. This prevents missing links, which Webkit-based browsers consider a violation of the spec.
Note that min-height
and max-height
are not acceptable. It must be the height
property.
More details here: Working with the CSS height
property and percentage values
2. CSS Relative & Absolute Positioning
Apply position: relative
to the parent and position: absolute
to the child.
Size the child with height: 100%
and width: 100%
, or use the offset properties: top: 0
, right: 0
, bottom: 0
, left: 0
.
With absolute positioning, percentage height works without a specified height on the parent.
3. Remove unnecessary HTML containers (recommended)
Is there a need for two containers around button
? Why not remove .item
or .item-inner
, or both? Although button
elements sometimes fail as flex containers, they can be flex items. Consider making button
a child of .container
or .item
, and removing gratuitous mark-up.
Here's an example:
.container {
height: 20em;
display: flex;
flex-direction: column;
border: 5px solid black
}
a {
flex: 1;
background: orange;
border-bottom: 1px solid white;
display: flex; /* nested flex container (for aligning text) */
align-items: center; /* center text vertically */
justify-content: center; /* center text horizontally */
}
<div class="container">
<a>Button</a>
<a>Button</a>
<a>Button</a>
</div>
4. Nested Flex Containers (recommended)
Get rid of percentage heights. Get rid of table properties. Get rid of vertical-align
. Avoid absolute positioning. Just stick with flexbox all the way through.
Apply display: flex
to the flex item (.item
), making it a flex container. This automatically sets align-items: stretch
, which tells the child (.item-inner
) to expand the full height of the parent.
Important: Remove specified heights from flex items for this method to work. If a child has a height specified (e.g. height: 100%
), then it will ignore the align-items: stretch
coming from the parent. For the stretch
default to work, the child's height must compute to auto
(full explanation).
Try this (no changes to HTML):
.container {
display: flex;
flex-direction: column;
height: 20em;
border: 5px solid black
}
.item {
display: flex; /* new; nested flex container */
flex: 1;
border-bottom: 1px solid white;
}
.item-inner {
display: flex; /* new; nested flex container */
flex: 1; /* new */
/* height: 100%; <-- remove; unnecessary */
/* width: 100%; <-- remove; unnecessary */
/* display: table; <-- remove; unnecessary */
}
a {
display: flex; /* new; nested flex container */
flex: 1; /* new */
align-items: center; /* new; vertically center text */
background: orange;
/* display: table-cell; <-- remove; unnecessary */
/* vertical-align: middle; <-- remove; unnecessary */
}
<div class="container">
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
<div class="item">
<div class="item-inner">
<a>Button</a>
</div>
</div>
</div>
jsFiddle
Solution 2
Specifying a flex attribute to the container worked for me:
.container {
flex: 0 0 auto;
}
This ensures the height is set and doesn't grow either.
Solution 3
Solution: Remove height: 100%
in .item-inner and add display: flex
in .item
Demo: https://codepen.io/tronghiep92/pen/NvzVoo
Solution 4
For Mobile Safari There is a Browser fix. you need to add -webkit-box for iOS devices.
Ex.
display: flex;
display: -webkit-box;
flex-direction: column;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
align-items: stretch;
if you're using align-items: stretch;
property for parent element, remove the height : 100%
from the child element.
Solution 5
I have had a similar issue in iOS 8, 9 and 10 and the info above couldn't fix it, however I did discover a solution after a day of working on this. Granted it won't work for everyone but in my case my items were stacked in a column and had 0 height when it should have been content height. Switching the css to be row and wrap fixed the issue. This only works if you have a single item and they are stacked but since it took me a day to find this out I thought I should share my fix!
.wrapper {
flex-direction: column; // <-- Remove this line
flex-direction: row; // <-- replace it with
flex-wrap: wrap; // <-- Add wrapping
}
.item {
width: 100%;
}
Related videos on Youtube
Comments
-
Ricardo Castañeda about 4 years
I want to have a vertical menu with a specific height.
Each child must fill the height of the parent and have middle-aligned text.
The number of children is random, so I have to work with dynamic values.
Div
.container
contains a random number of children (.item
) that always have to fill the height of the parent. To achieve that I used flexbox.For making links with text aligned to the middle I am using
display: table-cell
technique. But using table displays requires using a height 100%.My problem is that
.item-inner { height: 100% }
is not working in webkit (Chrome).- Is there a fix for this problem?
- Or is there a different technique to make all
.item
fill the height of the parent with text vertical aligned to middle?
Example here jsFiddle, should be viewed in Firefox and Chrome
.container { height: 20em; display: flex; flex-direction: column; border: 5px solid black } .item { flex: 1; border-bottom: 1px solid white; } .item-inner { height: 100%; width: 100%; display: table; } a { background: orange; display: table-cell; vertical-align: middle; }
<div class="container"> <div class="item"> <div class="item-inner"> <a>Button</a> </div> </div> <div class="item"> <div class="item-inner"> <a>Button</a> </div> </div> <div class="item"> <div class="item-inner"> <a>Button</a> </div> </div> </div>
-
vsync over 7 yearsit has now been fixed - bugs.chromium.org/p/chromium/issues/detail?id=426898
-
AlexMA over 7 yearsThis isn't specifically relevant to OP, but might be relevant for googlers who land here for "safari display absolute height 100% doesnt work" or something similar. I have an element like this inside a flex container and had to specify
top:0
andleft:0
to have it appear as expected. -
TylerH over 6 years@vsync hasn't been fixed yet: stackoverflow.com/questions/46226298/…
-
Reece Kenney over 6 yearsThanks, this helped me. Do flex children automatically take stretch to the height of their container? Is this why this works?
-
Michael Benjamin over 6 years@ReeceKenney, yes, to your questions. This is explained in my answer. See solution #4.
-
Alfrex92 over 5 yearsI fixed my issue using height:auto
-
littlewhywhat almost 5 yearsjust some remark taken from the explanation link of this great post - "align-items: stretch" makes flex children to expand across the cross axis of the container - that is to stretch children to the height, the flex container should have flex-direction as row.
-
flocbit almost 5 yearsI can confirm that using nested flex containers works best. We used flexbox inconsistently in our menu. Instead of using flex: 1 and display: flex on parent containers we used height: 100% at some places. Everything worked as expected after we replaced the corresponding definitions. Thanks @Michael_B for the hint! :)
-
DerMike over 4 years@JamesHarrington, CSS has grown over time and is complex ;-)
-
Jp_ about 4 yearsEach solution should be a different answer. How can I vote in a specific solution this way?
-
Raj kannan Iyyappan about 4 yearsNested Flex Containers - Get rid of the min height! Works great!
-
Chris Hayes over 3 yearsFixed it for me! What a lifesaver.
-
Big Money over 3 yearsomg thank you so much you saved me from so much headache!
display: -webkit-box;
is exactly what I needed. It turns out even in late 2020, iOS devices still don't have predictable flex support -
Mike-E over 3 yearsThank you so much for the "remove height" recommendation as that was the problem I have been spending the past hour trying to solve!
-
boatcoder over 3 yearsI had so wanted this to work, but I end up with the container off the bottom of the viewport
-
Nam Lê Quý almost 3 yearswork for me. thank you so much. before that don't understand why my height is only 1px on safari when redirect to another page.
-
vnoo over 2 yearsjsfiddle.net/49c1kzxv Hi, I just have a little edit :D change background from white to black. Can you see the white space next to the border? How can I remove it?
-
Michael Benjamin over 2 yearsAdd
body { margin: 0 }
. Will override the default margin on thebody
element. jsfiddle.net/ks6aztqr @vnoo -
vnoo over 2 years@MichaelBenjamin It does not fix my issue :D Can you please check my question? stackoverflow.com/questions/69134840/…