174

How can I tell a flexbox layout row consume the remaining vertical space in a browser window?

I have a 3-row flexbox layout. The first two rows are fixed height, but the 3rd is dynamic and I would like it to grow to the full height of the browser.

enter image description here

I have another flexbox in row-3 which creates a set of columns. To properly adjust elements within these columns I need them to understand the full height of the browser -- for things like background color and item alignments at the base. The major layout would ultimately resemble this:

enter image description here

.vwrapper {
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;
    justify-content: flex-start;
    align-items: stretch;
    align-content: stretch;
    //height: 1000px;
}
.vwrapper #row1 {
    background-color: red;
}
.vwrapper #row2 {
    background-color: blue;
}
.vwrapper #row3 {
    background-color: green;
    flex 1 1 auto;
    display: flex;
}
.vwrapper #row3 #col1 {
    background-color: yellow;
    flex 0 0 240px;
}
.vwrapper #row3 #col2 {
    background-color: orange;
    flex 1 1;
}
.vwrapper #row3 #col3 {
    background-color: purple;
    flex 0 0 240px;
}
<body>
    <div class="vwrapper">
        <div id="row1">
            this is the header
        </div>
        <div id="row2">
            this is the second line
        </div>
        <div id="row3">
            <div id="col1">
                col1
            </div>
            <div id="col2">
                col2
            </div>
            <div id="col3">
                col3
            </div>
        </div>
    </div>
</body>

I've tried adding a height attribute, which does work when I set it to a hard number but not when I set it to 100%. I understand height: 100% isn't working, because the content isn't filling the browser window, but can I replicate the idea using the flexbox layout?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Nicholas Pappas
  • 10,439
  • 12
  • 54
  • 87

4 Answers4

183

You should set height of html, body, .wrapper to 100% (in order to inherit full height) and then just set a flex value greater than 1 to .row3 and not on the others.

.wrapper, html, body {
    height: 100%;
    margin: 0;
}
.wrapper {
    display: flex;
    flex-direction: column;
}
#row1 {
    background-color: red;
}
#row2 {
    background-color: blue;
}
#row3 {
    background-color: green;
    flex:2;
    display: flex;
}
#col1 {
    background-color: yellow;
    flex: 0 0 240px;
    min-height: 100%;/* chrome needed it a question time , not anymore */
}
#col2 {
    background-color: orange;
    flex: 1 1;
    min-height: 100%;/* chrome needed it a question time , not anymore */
}
#col3 {
    background-color: purple;
    flex: 0 0 240px;
    min-height: 100%;/* chrome needed it a question time , not anymore */
}
<div class="wrapper">
    <div id="row1">this is the header</div>
    <div id="row2">this is the second line</div>
    <div id="row3">
        <div id="col1">col1</div>
        <div id="col2">col2</div>
        <div id="col3">col3</div>
    </div>
</div>

DEMO


EDIT, as mention by @Basj , the code can be shorten . We can also nowdays use grid widely implemented : Below an example with grid for the visitors :

body {
    height: 100vh;
    display: grid;
    grid-template-rows: auto auto 1fr;
    margin: 0;
    background-color: orange;
    grid-template-columns: 240px 1fr 240px;
}

[id^=row]{ grid-column: 1/-1 }

#row1 { background-color: red; }
#row2 { background-color: blue; }
#row3 { background-color: green; }
#col1 { background-color: yellow; }
#col3 { background-color: purple; }
<div id="row1">this is the header</div>
<div id="row2">this is the second line</div>
<div id="col1">col1</div>
<div id="col2">col2</div>
<div id="col3">col3</div>
Fauzan Edris
  • 136
  • 3
  • 13
G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
  • Any way to do this while also having the content divs expand to fill their contents? [Forked your example here](http://fiddle.jshell.net/Lhhh3wde/). – iameli May 06 '15 at 00:33
  • @iameli , use min-height for chrome instead height http://fiddle.jshell.net/Lhhh3wde/1/ – G-Cyrillus May 06 '15 at 07:20
  • 2
    The JSFiddle is brokened – Joel Peltonen Feb 01 '19 at 09:58
  • 2
    Here is the working codepen demo: https://codepen.io/mprinc/pen/JjGQvae and explanation in the similar question: https://stackoverflow.com/a/63174085/257561 – mPrinC Jul 30 '20 at 13:20
  • fiddle replaced by a codepen that should not vanish, it's a copy of the snippet . **Note** that min-height is not needed anymore in today's chrome version. – G-Cyrillus Jul 30 '20 at 13:40
  • Setting 100% to body, html and the container after that and so on definitely works. – Leslie YJ Nov 16 '20 at 02:16
  • @G-Cyrillus If you put content in `col2` that overflows the screen height and you scroll down, the columns are not growing. Can you fix that somehow? – Toxiro Jan 13 '21 at 13:39
  • @Toxiro Sounds like that's a new question that you should post. – trusktr May 01 '21 at 07:06
  • Great! Here is a slightly simplified version: https://stackoverflow.com/a/73261320/1422096 – Basj Aug 06 '22 at 16:52
  • @Basj okay, you only removed the OP's wrapper and obsolete CSS for chrome (notified by comments :) ) Also, grid should also be proposed to make a shorter CSS without the wrapper https://codepen.io/gc-nomade/pen/GRxdYwP – G-Cyrillus Aug 06 '22 at 17:18
  • Yes @G-Cyrillus, it was a minimal modification - full credit to you for the solution :) – Basj Aug 06 '22 at 17:25
  • 1
    @Basj its fine with me , i like better the grid display for main and complex layouts that now works everywhere .I do not dislike, flex, and float, which are efficient for their jobs ;) (nor column CSS or table display) We do have a really good bunch of tools for layouts nowdays. – G-Cyrillus Aug 06 '22 at 17:30
27

set the wrapper to height 100%

.vwrapper {
  display: flex;
  flex-direction: column;

  flex-wrap: nowrap;
  justify-content: flex-start;
  align-items: stretch;
  align-content: stretch;

  height: 100%;
}

and set the 3rd row to flex-grow

#row3 {
   background-color: green;
   flex: 1 1 auto;
   display: flex;
}

demo

vals
  • 61,425
  • 11
  • 89
  • 138
5

Let me show you another way that works 100%. I will also add some padding for the example.

<div class = "container">
  <div class = "flex-pad-x">
    <div class = "flex-pad-y">
      <div class = "flex-pad-y">
        <div class = "flex-grow-y">
         Content Centered
        </div>
      </div>
    </div>
  </div>
</div>

.container {
  position: fixed;
  top: 0px;
  left: 0px;
  bottom: 0px;
  right: 0px;
  width: 100%;
  height: 100%;
}

  .flex-pad-x {
    padding: 0px 20px;
    height: 100%;
    display: flex;
  }

  .flex-pad-y {
    padding: 20px 0px;
    width: 100%;
    display: flex;
    flex-direction: column;
  }

  .flex-grow-y {
    flex-grow: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
   }

As you can see we can achieve this with a few wrappers for control while utilising the flex-grow & flex-direction attribute.

1: When the parent "flex-direction" is a "row", its child "flex-grow" works horizontally. 2: When the parent "flex-direction" is "columns", its child "flex-grow" works vertically.

Hope this helps

Daniel

GaddMaster
  • 331
  • 3
  • 14
  • 1
    `div` overkill. – John Oct 25 '19 at 20:40
  • You can remove one of your `flex-pad-y` :) – Eoin May 07 '20 at 16:42
  • 2
    Nice..! This is the only example which managed to make my "content"
    (in between my header and footer) fill the entire screen height. All the other examples seem to ignore the "height:100%" attribute.
    – Mike Gledhill Jun 28 '20 at 12:26
  • 2
    It is a cool solutions. I know John says above DIV overkill, but I do not agree. You need the four divs to utilise flex grow both horizontally and vertically (Vertically been the important one!). Glad I could help ! Having the four DIVs gives you a lot of flexibility. Once you start trying to remove DIVs , that flexibility starts to wither ! – GaddMaster Jun 29 '20 at 13:06
5

The accepted answer is very good, but I noticed the wrapper was not needed, as well as a few other CSS rules. Here is a minimal version:

html, body { height: 100%; }
body { display: flex; flex-direction: column; margin: 0; }
#row1 { background-color: red; }
#row2 { background-color: blue; }
#row3 { background-color: green; flex: 2; display: flex; }
#col1 { background-color: yellow; flex: 0 0 240px; }
#col2 { background-color: orange; flex: 1 1; }
#col3 { background-color: purple; flex: 0 0 240px; }
<div id="row1">this is the header</div>
<div id="row2">this is the second line</div>
<div id="row3">
    <div id="col1">col1</div>
    <div id="col2">col2</div>
    <div id="col3">col3</div>
</div>
Basj
  • 41,386
  • 99
  • 383
  • 673