Nick
Nick

Reputation: 780

CSS height issue with flex box inside flex box

I am having a problem with flex boxes contained inside flex boxes. The JS Fiddle at http://jsfiddle.net/fr077nn2/ contains the following code:

    #container{
      position: absolute;
      height: 100%;
      width: 100%;
      border: 3px solid yellow;
    }
    .app {
      display: flex;
      flex-direction: column;
      height: 100%;
      border: 3px solid black;
    }
    .app-header {
      border: 3px solid red;
    }
    .app-content {
      border: 3px solid green;
      flex: 1;
      overflow: hidden;
    }
    .app-footer {
      border: 3px solid blue;
    }
   <div id="container">
      <div class="app">
        <div class="app-header">HEADER1</div>
        <div class="app-content">
          <div class="app">
            <div class="app-header">HEADER2</div>
            <div class="app-content">CONTENT2</div>
            <div class="app-footer">FOOTER2</div>
          </div>
        </div>
        <div class="app-footer">FOOTER1</div>
      </div>
    </div>

I am trying to get the .app-content DIVs fill up the remaining space of the parent .app DIV. It works well for the outer boxes, as shown in the fiddle. However, for the inner boxes, CONTENT2 is not filling the remaining space. I suspect that height:100% does not work in that case because the height of the parent DIV is not properly known... any suggestion how to achieve the above properly?

Edit: Works fine on Firefox as expected not on Chrome.

Upvotes: 16

Views: 16621

Answers (3)

Salman Arshad
Salman Arshad

Reputation: 272006

Generally speaking, 100% height works when the parent has a well defined height. In your example, the outermost app-content does not have an explicit height which is why 100% height on its child does not work.

A simple workaround is to use relative-absolute positioning to size the child:

#container {
  position: absolute;
  height: 100%;
  width: 100%;
  border: 3px solid yellow;
}
.app {
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 3px solid black;
}
.app-header {
  border: 3px solid red;
}
.app-content {
  border: 3px solid green;
  flex: 1;
  /* added property */
  position: relative;
}
.app-footer {
  border: 3px solid blue;
}
/* added rule */
.app-content > .app {
  height: auto;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
}
/* scrollbar and border correction */
body {
  margin: 0;
  padding: 0;
}
div {
  box-sizing: border-box;
}
<div id="container">
  <div class="app">
    <div class="app-header">HEADER1</div>
    <div class="app-content">
      <div class="app">
        <div class="app-header">HEADER2</div>
        <div class="app-content">CONTENT2</div>
        <div class="app-footer">FOOTER2</div>
      </div>
    </div>
    <div class="app-footer">FOOTER1</div>
  </div>
</div>

Upvotes: 9

misterManSam
misterManSam

Reputation: 24692

Why not simplify?

Using your current markup

This seems like a lot of unnecessary HTML.

You need to nest the flex all the way down. In this example, the top flex container has height: 100vh to take up the entire height of the viewport. Some of the flex children are also flex parents, they get display: flex along with flex: 1 so they will grow and shrink and their children can expand.

Example

* {
  margin: 0;
  padding: 0;
  border: 0;
}
div {
  box-sizing: border-box;
}
#container {
  height: 100vh;
  border: 3px solid yellow;
  display: flex;
}
.app {
  display: flex;
  flex: 1;
  flex-direction: column;
  border: 3px solid black;
}
.app-header {
  border: 3px solid red;
}
.app-content {
  border: 3px solid green;
  display: flex;
  flex: 1;
  overflow: hidden;
}
.app-footer {
  border: 3px solid blue;
}
<div id="container">
  <div class="app">
    <div class="app-header">HEADER1</div>
    <div class="app-content">
      <div class="app">
        <div class="app-header">HEADER2</div>
        <div class="app-content">CONTENT2</div>
        <div class="app-footer">FOOTER2</div>
      </div>
    </div>
    <div class="app-footer">FOOTER1</div>
  </div>
</div>


Simplified Example

We can drastically reduce the markup and eliminate the need to nest the flex. The content is given flex: 1 and will expand to fill all the space left over from the headers and footers.

In this example, the body itself is the flex container, this could be replaced with a top-level div wrapper.

* {
  margin: 0;
  box-sizing: border-box;
}
body {
  height: 100vh;
  display: flex;
  flex-direction: column;
  border: 3px solid black;
}
.app-header {
  border: 3px solid red;
}
.app-content {
  border: 3px solid green;
  flex: 1;
}
.app-footer {
  border: 3px solid blue;
}
<div class="app-header">HEADER1</div>

<div class="app-header">HEADER2</div>

<div class="app-content">CONTENT2</div>

<div class="app-footer">FOOTER2</div>

<div class="app-footer">FOOTER1</div>

Upvotes: 1

Morpfh
Morpfh

Reputation: 4093

Not sure if this is OK / fit your needs, but at least it is flexing in Chrome + FF ;P Perhaps a nesting issue.

Flex on container + flex on content:

http://jsfiddle.net/fr077nn2/2/

#container{
  position: absolute;
  height: 100%;
  width: 100%;
  border: 3px solid yellow;
  display: flex;
  flex-direction: column;
}
.app {
  display: flex;
  flex-direction: column;
  border: 3px solid black;
  flex-grow: 1;
}
.app-header {
  border: 3px solid red;
}
.app-content {
  border: 3px solid green;
  overflow: hidden;
  flex-grow: 1;
  display: flex;
}
.app-footer {
  border: 3px solid blue;
}

Upvotes: 1

Related Questions