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>
Solution: Remove
height: 100%
in .item-inner and adddisplay: flex
in .itemDemo: https://codepen.io/tronghiep92/pen/NvzVoo
The Problem
It's not working because you're using percentage height in a way that doesn't conform with the traditional implementation of the spec.
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 meheight: 100%
. Chrome looks to the parent (.item
) for reference and responds: 100% of what? I don't see anything (ignoring theflex: 1
rule that is there). As a result, it appliesheight: 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 withflex-basis
(any numerical value works (auto
won't), includingflex-basis: 0
). As of this writing, however, this solution fails in Safari.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
andmax-height
are not acceptable. It must be theheight
property.More details here: Working with the CSS
height
property and percentage values2. CSS Relative & Absolute Positioning
Apply
position: relative
to the parent andposition: absolute
to the child.Size the child with
height: 100%
andwidth: 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? Althoughbutton
elements sometimes fail as flex containers, they can be flex items. Consider makingbutton
a child of.container
or.item
, and removing gratuitous mark-up.Here's an example:
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 setsalign-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 thealign-items: stretch
coming from the parent. For thestretch
default to work, the child's height must compute toauto
(full explanation).Try this (no changes to HTML):
jsFiddle
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!
For Mobile Safari There is a Browser fix. you need to add -webkit-box for iOS devices.
Ex.
if you're using
align-items: stretch;
property for parent element, remove theheight : 100%
from the child element.