602
votes

I'm trying to fill the vertical space of a flex item inside a Flexbox.

.container {
  height: 200px;
  width: 500px;
  display: flex;
  flex-direction: row;
}
.flex-1 {
  width: 100px;
  background-color: blue;
}
.flex-2 {
  position: relative;
  flex: 1;
  background-color: red;
}
.flex-2-child {
  height: 100%;
  width: 100%;
  background-color: green;
}
<div class="container">
  <div class="flex-1"></div>
  <div class="flex-2">
    <div class="flex-2-child"></div>
  </div>
</div>

And here's the JSFiddle

flex-2-child doesn't fill the required height except in the two cases where:

  1. flex-2 has a height of 100% (which is weird because a flex item has a 100% by default + it is buggy in Chrome)
  2. flex-2-child has a position absolute which is also inconvenient

This doesn't work in Chrome or Firefox currently.

11
what is the problem with using height:100%; for .flex-2 ?rmagnum2002
It defies the purpose of the flex item which is to fill the content by itself and it's giving me the weirdest bug in chrome where the height goes back to zero whenever I resize the windowRaz
Actually, the latest version of Firefox is the only one working properlyRaz
Currently, there are significant differences in behavior among browsers when it comes to rendering percentage heights in flexbox: stackoverflow.com/a/35537510/3597276Michael Benjamin
Yep, Chrome has some issues, especially with nested flexboxes. For example I've got a nested flex box with children that have height:100% but they are rendering with natural height instead. And the weird thing is if I change their height to auto, then they render as height:100% like I was trying to do. It is definitely not intuitive if that's how it should work.trusktr

11 Answers

448
votes

Use align-items: stretch

Similar to David Storey's answer, my workaround is:

.flex-2 {
    display: flex;
    align-items: stretch;
}

Note that height: 100% should be removed from the child component (see comments).

Alternatively to align-items, you can use align-self just on the .flex-2-child item you want stretched.

282
votes

I have answered a similar question here.

I know you have already said position: absolute; is inconvenient, but it works. See below for further information on fixing the resize issue.

Also see this jsFiddle for a demo, although I have only added WebKit prefixes so open in Chrome.

You basically have two issues which I will deal with separately.

  1. Getting the child of a flex-item to fill height 100%
  • Set position: relative; on the parent of the child.
  • Set position: absolute; on the child.
  • You can then set width/height as required (100% in my sample).
  1. Fixing the resize scrolling "quirk" in Chrome
  • Put overflow-y: auto; on the scrollable div.
  • The scrollable div must have an explicit height specified. My sample already has height 100%, but if none is already applied you can specify height: 0;

See this answer for more information on the scrolling issue.

239
votes

If I understand correctly, you want flex-2-child to fill the height and width of its parent, so that the red area is fully covered by the green?

If so, you just need to set flex-2 to use Flexbox:

.flex-2 {
    display: flex;
}

Then tell flex-2-child to become flexible:

.flex-2-child {
    flex: 1;
}

See http://jsfiddle.net/2ZDuE/10/

The reason is that flex-2-child is not a Flexbox item, but its parent is.

26
votes

I suppose that Chrome's behavior is more consistent with the CSS specification (though it's less intuitive). According to Flexbox specification, the default stretch value of align-self property changes only the used value of the element's "cross size property" (height, in this case). And, as I understand the CSS 2.1 specification, the percentage heights are calculated from the specified value of the parent's height, not its used value. The specified value of the parent's height isn't affected by any flex properties and is still auto.

Setting an explicit height: 100% makes it formally possible to calculate the percentage height of the child, just like setting height: 100% to html makes it possible to calculate the percentage height of body in CSS 2.1.

19
votes

I found the solution by myself. Suppose you have the CSS below:

.parent {
  align-items: center;
  display: flex;
  justify-content: center;
}

.child {
  height: 100%; <- didn't work
}

In this case, setting the height 100% will not work, so I set the margin-bottom rule to auto, like:

.child {
  margin-bottom: auto;
}

And the child will be aligned to the topmost of the parent.

You can also use the align-self rule anyway if you prefer:

.child {
  align-self: flex-start;
}
7
votes

This can also be solved with align-self: stretch; on the element we want to be stretched.

Sometimes it is desirable to only stretch one item in a Flexbox setup.

.container {
  height: 200px;
  width: 500px;
  display: flex;
  flex-direction: row;
}
.flex-1 {
  width: 100px;
  background-color: blue;
}
.flex-2 {
  position: relative;
  flex: 1;
  align-self: stretch;
  background-color: red;
}
.flex-2-child {
  background-color: green;
}
<div class="container">
  <div class="flex-1"></div>
  <div class="flex-2">
    <div class="flex-2-child"></div>
  </div>
</div>
4
votes

An idea would be that display:flex; with flex-direction: row; is filling the container div with .flex-1 and .flex-2, but that does not mean that .flex-2 has a default height:100%;, even if it is extended to full height.

And to have a child element (.flex-2-child) with height:100%;, you'll need to set the parent to height:100%; or use display:flex; with flex-direction: row; on the .flex-2 div too.

From what I know, display:flex will not extend all your child elements height to 100%.

A small demo, removed the height from .flex-2-child and used display:flex; on .flex-2: http://jsfiddle.net/2ZDuE/3/

3
votes

.container {
    height: 200px;
    width: 500px;
    display: -moz-box;
    display: -webkit-flexbox;
    display: -ms-flexbox;
    display: -webkit-flex;
    display: -moz-flex;
    display: flex;
    -webkit-flex-direction: row;
    -moz-flex-direction: row;
    -ms-flex-direction: row;
    flex-direction: row;
}
.flex-1 {
   flex:1 0 100px;
    background-color: blue;
}
.flex-2 {
    -moz-box-flex: 1;
    -webkit-flex: 1;
    -moz-flex: 1;
    -ms-flex: 1;
    flex: 1 0 100%;
    background-color: red;
}
.flex-2-child {
    flex: 1 0 100%;
    height: 100%;
    background-color: green;
}
<div class="container">
    <div class="flex-1"></div>
    <div class="flex-2">
        <div class="flex-2-child"></div>
    </div>
</div>

http://jsfiddle.net/2ZDuE/750/

1
votes

fun fact: height-100% works in the latest chrome; but not in safari;


so solution in tailwind would be

"flex items-stretch"

https://tailwindcss.com/docs/align-items

and be applied recursively to the child's child's child ...

-9
votes

.container { . . . . align-items: stretch; . . . . }

-13
votes

This is my solution using css+.

First of all, if the first child (flex-1) should be 100px, it shouldn't be flex.

In css+ in fact you can set flexible and/or static elements (columns or rows) and your example become as easy as this:

<div class="container">
  <div class="EXTENDER">
    <div class="COLS">
      <div class="CELL _100px" style="background-color:blue">100px</div>
      <div class="CELL _FLEX" style="background-color:red">flex</div>
    </div>
  </div>
</div>

Container CSS:

.container {
    height: 200px;
    width: 500px;
    position: relative;
}

And obviously include css+ 0.2 core.

Here is the fiddle.