6

If I make a flexbox with 2 children and column flow and set the second child to flex-grow 1 the second child expands to fill the flexbox. This works

(ps: Didn't want to clutter the example with safari support so use Chrome or Firefox)

* {
  box-sizing: border-box;
}
html, body {
  margin: 0;
  width: 100%;
  height: 100%;
  color: white;
}
#outer {
  display: flex;
  flex-flow: column;
  height: 100%;
}
#top { 
  background-color: red;
}
#bottom {
  background-color: blue;
  flex: 1 0 auto;
}
<div id="outer">
  <div id="top">top</div>
  <div id="bottom">bottom (blue)</div>
</div>
  

But, if I then put a child #inside inside #bottom and set its height to 100% it doesn't increase its height to match even though the flexbox has stretched #bottom.

added css

#inside {
  background-color: green;
  height: 100%;
}

html

<div id="outer">
  <div id="top">top</div>
  <div id="bottom">
    <div id="inside">inside</div>  <!- added ->
  </div>
</div>

* {
  box-sizing: border-box;
}
html, body {
  margin: 0;
  width: 100%;
  height: 100%;
  color: white;
}
#outer {
  display: flex;
  flex-flow: column;
  height: 100%;
}
#top { 
  background-color: red;
}
#bottom {
  background-color: blue;
  flex: 1 0 auto;
}
#inside {
  background-color: green;
  height: 100%;
}
<div id="outer">
  <div id="top">top</div>
  <div id="bottom">
    <div id="inside">inside (green)</div>
  </div>
</div>

So I add a height: 100% to #bottom but now bottom is as big as #outer instead of the flex stretched size.

#bottom {
  background-color: blue;
  flex: 1 0 auto;
  height: 100%;   /* added */
} 

* {
  box-sizing: border-box;
}
html, body {
  margin: 0;
  width: 100%;
  height: 100%;
  color: white;
}
#outer {
  display: flex;
  flex-flow: column;
  height: 100%;
}
#top { 
  background-color: red;
}
#bottom {
  background-color: blue;
  flex: 1 0 auto;
  height: 100%;
}
#inside {
  background-color: green;
  height: 100%;
}
<div id="outer">
  <div id="top">top</div>
  <div id="bottom">
    <div id="inside">inside (green) (would not scroll if working)</div>
  </div>
</div>

How do I get #bottom to stretch to fit the flexbox and also get a the child #inside to be 100% height of its container #bottom?

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
gman
  • 100,619
  • 31
  • 269
  • 393

2 Answers2

2

Flex has a quirk where you need to set the height to 0.

Change the #bottom rule's height property to this height: 0;

For the inside to work I changed it to "position: absolute" and as well added a position:relative to the bottom

Update

If you don't want to use absolute position, you can set these 2 css rules like this:

(Note though, that this propagates the original issue if a new inner div is used like the first one)

#bottom {
  position: relative;
  background-color: blue;
  flex: 1 0 auto;
  height: 0;
  display: flex;
}
#inside {
  background-color: green;
  flex: 1 0 auto;
}

Sample using "position: absolute"

* {
  box-sizing: border-box;
}
html, body {
  margin: 0;
  width: 100%;
  height: 100%;
  color: white;
}
#outer {
  display: flex;
  flex-flow: column;
  height: 100%;
}
#top { 
  background-color: red;
}
#bottom {
  position: relative;
  background-color: blue;
  flex: 1 0 auto;
  height: 0;
}
#inside {
  background-color: green;
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}
<div id="outer">
  <div id="top">top</div>
  <div id="bottom">
    <div id="inside">inside (would not scroll if working)</div>
  </div>
</div>
Asons
  • 84,923
  • 12
  • 110
  • 165
  • Making `#bottom` a flex just propagates the original issue. If I put another `div` inside `#inside` and set it to `height: 100%` it fails. You're original solution with `position: absolute` fixes things so they work *like normal* as in they work just like when not using flex. That seems a better solution than to have to make all children forever a flex. – gman Oct 14 '15 at 13:17
  • Yeah, might be so, didn't go that far in my testing. So if you need to set something 100% it seems that position absolute is need in the end. Will update my answer with that statement. – Asons Oct 14 '15 at 13:20
  • 1
    Having to *make all children forever a flex* is not that far off from having to apply `height: 100%` at every level. Except that when you create flex containers you enable all the benefits of flex properties. – Michael Benjamin Oct 14 '15 at 13:58
  • The difference is there is code all over the net that uses height: 100%. Ideally you should be able to take any chunk of HTML, stick it in a container and have it work. You shouldn't have to go through each child of that chunk of HTML and have to adjust its CSS just because it's in one container or another. The `position: absolute;` solution solves that. The `#bottom` to flex does not. – gman Oct 14 '15 at 14:04
  • Assuming that the parent always has a specified height, then yes, you should be able to insert HTML blocks (modules?) into the existing code and have it work... In your question, it gave the impression that you wanted to nest ONE child in `#bottom`. It didn't specify that nesting would continue indefinitely and the HTML blocks would contain `height: 100%`. My flex solution works, but it may not be appropriate for your use-case. – Michael Benjamin Oct 14 '15 at 14:12
  • It shouldn't have to. Any rational developer just wants things to go back to normal. In other words to work exactly as things had before elements were put inside a flexbox. A solution that only works if it's one element deep isn't a solution IMO. Thanks a ton for the working solution. – gman Oct 14 '15 at 14:15
  • You're welcome. But I'm only saying these things because you seem averse to nesting flexboxes. Otherwise, by simply adding two lines of code at each level, your task would be done. – Michael Benjamin Oct 14 '15 at 14:19
  • Here's the point. You should be able to take some HTML chunk and stick it in a flexbox and have it work as though it was outside the box. [Here's a chunk](http://jsfiddle.net/greggman/jx45a0v2/). Try to get it work in a flexbox using your first solution. – gman Oct 14 '15 at 14:46
  • http://jsfiddle.net/jx45a0v2/2/ ... (I hadn't seen your comment earlier. As long as the CSS is in place, you can stick the HTML in the flexbox) – Michael Benjamin Oct 14 '15 at 15:14
-1

How do I get #bottom to stretch to fit the flexbox and also get a the child #inside to be 100% height of its container #bottom?

Just add two lines of code to the CSS.

CSS

#bottom {
    background-color: blue;
    flex: 1 0 auto;
    display: flex; /* NEW */
}

#inside {
    flex: 1; /* NEW */
    background-color: green;
}

DEMO: http://jsfiddle.net/wf2L8dse/

Here's what's happening:

You have a flex container (#outer) with two flex items (#top and #bottom).

#outer is in column alignment.

#bottom has flex: 1 (i.e., flex-grow: 1), so it occupies all available height in the container.

A new element (#inside) is made a child of #bottom and must occupy the same height as parent.

Solution:

Make #bottom a (nested) flexbox. This activates default flex rules.

One such rule is align-items: stretch, which tells flex items (#inside) to stretch the full height of their container. (Height, in this case, because the flex-direction is row, by default.)

Then apply flex: 1 (or flex-grow: 1) to #inside, so it expands the full width of the container.


Addressing the height: 100% issue

I'm not sure there's anything wrong with your code. You have applied height: 100% to #inside and, as required by the spec when using percentage heights, specified a height for all parent elements including body and the root element (html).

The only thing you may want to consider (to remove the vertical scrollbar on the browser window), is applying overflow: hidden to body.

DEMO: http://jsfiddle.net/wf2L8dse/1/

Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • The problem with this solution it just propagates the original bug/issue. If I put yet another `div` inside `#inside` and set that to `height: 100%` it fails – gman Oct 14 '15 at 13:15
  • Your `height: 100%` is fine. Not sure there's a problem there. I updated my answer with further guidance. – Michael Benjamin Oct 14 '15 at 13:49
  • I'm not sure what you mean. What I want is for `#inside` to fill its container. What is happening in your bottom fiddle is that `#inside` is becoming larger than its container. You're hiding that fact by setting `overflow: hidden` on the html,body. – gman Oct 14 '15 at 14:01
  • Is there a defined height for `#top` or is it dynamic? – Michael Benjamin Oct 14 '15 at 14:04
  • It's whatever it is. That's the entire point of using a flexbox with flex-grow. You don't have to set specific heights. You tell the flexbox which children grow, which stay the same size and which shrink. After it's done that you're left with whatever it has chosen. The whole point of the original question is to then be able to stick things in those flexed children and have them work like normal, meaning if a child of flexed box, in this case `#inside`, has a height of 100% it should stretch to fit its container. That wasn't happening, hence the original question. – gman Oct 14 '15 at 14:08
  • Everything you wrote in your comment supports my first answer ;-) – Michael Benjamin Oct 14 '15 at 14:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/92275/discussion-between-gman-and-michael-b). – gman Oct 14 '15 at 14:30
  • You piqued my curiousity :-) http://stackoverflow.com/q/33129660/3597276 (Not saying it's going to help you, just wondering if it can be done in a standard way) – Michael Benjamin Oct 14 '15 at 15:43