158

Consider the following HTML/css code sample:

<div id="container">
    <div id="up">Text<br />Text<br />Text<br /></div>
    <div id="down">Text<br />Text<br />Text<br /></div>
</div>
#container { width: 300px; height: 300px; border:1px solid red;}
#up { background: green; }
#down { background:pink;}

where I have a container div with two children (also here: http://jsfiddle.net/S8g4E/). The first child has a given height. How can I make the second child to occupy the "free space" of the container div without giving a specific height?

In the example, the pink div should occupy also the white space.


Similar to this question: How to make div occupy remaining height?

But I don't want to give position absolute.

Thomas
  • 17,016
  • 4
  • 46
  • 70
Alvaro
  • 9,247
  • 8
  • 49
  • 76
  • 2
    I tried als giving second child height 100% but doesn't work: http://jsfiddle.net/S8g4E/1/ – Alvaro Jun 27 '12 at 12:15

9 Answers9

221

Expanding the #down child to fill the remaining space of #container can be accomplished in various ways depending on the browser support you wish to achieve and whether or not #up has a defined height.

Samples

.container {
  width: 100px;
  height: 300px;
  border: 1px solid red;
  float: left;
}
.up {
  background: green;
}
.down {
  background: pink;
}
.grid.container {
  display: grid;
  grid-template-rows: 100px;
}
.flexbox.container {
  display: flex;
  flex-direction: column;
}
.flexbox.container .down {
  flex-grow: 1;
}
.calc .up {
  height: 100px;
}
.calc .down {
  height: calc(100% - 100px);
}
.overflow.container {
  overflow: hidden;
}
.overflow .down {
  height: 100%;
}
<div class="grid container">
  <div class="up">grid
    <br />grid
    <br />grid
    <br />
  </div>
  <div class="down">grid
    <br />grid
    <br />grid
    <br />
  </div>
</div>
<div class="flexbox container">
  <div class="up">flexbox
    <br />flexbox
    <br />flexbox
    <br />
  </div>
  <div class="down">flexbox
    <br />flexbox
    <br />flexbox
    <br />
  </div>
</div>
<div class="calc container">
  <div class="up">calc
    <br />calc
    <br />calc
    <br />
  </div>
  <div class="down">calc
    <br />calc
    <br />calc
    <br />
  </div>
</div>
<div class="overflow container">
  <div class="up">overflow
    <br />overflow
    <br />overflow
    <br />
  </div>
  <div class="down">overflow
    <br />overflow
    <br />overflow
    <br />
  </div>
</div>

Grid

CSS's grid layout offers yet another option, though it may not be as straightforward as the Flexbox model. However, it only requires styling the container element:

.container { display: grid; grid-template-rows: 100px }

The grid-template-rows defines the first row as a fixed 100px height, and the remain rows will automatically stretch to fill the remaining space.

I'm pretty sure IE11 requires -ms- prefixes, so make sure to validate the functionality in the browsers you wish to support.

Flexbox

CSS3's Flexible Box Layout Module (flexbox) is now well-supported and can be very easy to implement. Because it is flexible, it even works when #up does not have a defined height.

#container { display: flex; flex-direction: column; }
#down { flex-grow: 1; }

It's important to note that IE10 & IE11 support for some flexbox properties can be buggy, and IE9 or below has no support at all.

Calculated Height

Another easy solution is to use the CSS3 calc functional unit, as Alvaro points out in his answer, but it requires the height of the first child to be a known value:

#up { height: 100px; }
#down { height: calc( 100% - 100px ); }

It is pretty widely supported, with the only notable exceptions being <= IE8 or Safari 5 (no support) and IE9 (partial support). Some other issues include using calc in conjunction with transform or box-shadow, so be sure to test in multiple browsers if that is of concern to you.

Other Alternatives

If older support is needed, you could add height:100%; to #down will make the pink div full height, with one caveat. It will cause overflow for the container, because #up is pushing it down.

Therefore, you could add overflow: hidden; to the container to fix that.

Alternatively, if the height of #up is fixed, you could position it absolutely within the container, and add a padding-top to #down.

And, yet another option would be to use a table display:

#container { width: 300px; height: 300px; border: 1px solid red; display: table;}
#up { background: green; display: table-row; height: 0; }
#down { background: pink; display: table-row;}​
jeffjenx
  • 17,041
  • 6
  • 57
  • 99
  • 4
    I would like #down to have #container height - #up height. So overflow hidden is not what I'm looking for. And also don't want to use absolute position. Thanks! – Alvaro Jun 27 '12 at 12:22
  • @Alvaro, I've added another option, using table displays. Disadvantage here is compatibility. P.S. An element positioned absolutely inside a container with `position: relative;` positions it relative to the container, not the window. So, that should be a viable option. – jeffjenx Jun 27 '12 at 12:25
  • Could you please give me an example of what you mean with 'An element positioned absolutely inside a container with position: relative; positions it relative to the container, not the window.' Your table solution isn't exactly what Im looking for:I would like #down to have #container height - #up height. (In this solution #down height = #container height) – Alvaro Jun 27 '12 at 12:31
  • 2
    Table-row should be working for you, see [this jsFiddle](http://jsfiddle.net/S8g4E/12/) for proof. The position absolute method, will not be able to yield the same results as this fiddle, so we can scratch that off the list (#down and #container will have the same height in that scenario). – jeffjenx Jun 27 '12 at 12:38
  • 3
    You're asking a lot, @Alvaro. CSS is not a scripting language; it can't calculate stuff. You're stuck with either illusions or js. – Jezen Thomas Jun 27 '12 at 12:38
  • @Alvaro with the table solution down height is equal to container height. [This jsfiddle](http://jsfiddle.net/S8g4E/15/) will show this pretty clearly. – Josh Mein Jun 27 '12 at 12:50
  • Thank you, this is the answer I was seeking, The table one. I just missed MrSlayer last comment. Thanks. – Alvaro Jun 27 '12 at 12:51
  • @Jezen, I used Javascript codes to do the calculation first, but then found when I have animation involved, it really became a hassle. You have to do setTimeout to delay the setting of #down's height so that #up has finished animation. If css can resolve it is great. I feel the display:table solution is great. – gm2008 Jun 15 '14 at 00:57
  • 1
    @Quantastical, thanks for your help, but in your latest edit you just copied the answer I posted. Some mention about it at least would be nice. – Alvaro Nov 25 '14 at 11:47
  • @Alvaro Actually, I didn't just copy the answer you posted, but I do apologize if you feel cheated or something. I received an upvote on my answer, so I updated it after re-reading the original content, and provided new content after seeing how frequently viewed this question was. I did this in order to ensure future visitors had all the available options in the accepted answer. I mean no disrespect to you, your question, or your answer. I've updated my answer to ensure you receive all credit for coming up with the idea of using CSS3 calc units. – jeffjenx Nov 25 '14 at 14:28
  • Of course, no problem. Sorry if I misunderstood. Thanks for the new edit. – Alvaro Nov 25 '14 at 15:43
  • That concise flexbox solution totally made my problem work out: "google maps fill remaining space in variable width and height container in angular + ionic" (including the keywords here for that reason). Nothing else worked, max-height was never respected and so on.) All the other "responsive" solutions I googled just "responsively" changed height corresponding to width. But I wanted to just fill all available space. https://imgur.com/gallery/BIo7MBq – Arno Teigseth Apr 29 '21 at 20:08
24

Its been almost two years since I asked this question. I just came up with css calc() that resolves this issue I had and thought it would be nice to add it in case someone has the same problem. (By the way I ended up using position absolute).

http://jsfiddle.net/S8g4E/955/

Here is the css

#up { height:80px;}
#down {
    height: calc(100% - 80px);//The upper div needs to have a fixed height, 80px in this case.
}

And more information about it here: http://css-tricks.com/a-couple-of-use-cases-for-calc/

Browser support: http://caniuse.com/#feat=calc

Alvaro
  • 9,247
  • 8
  • 49
  • 76
  • 1
    I, too, have been using CSS3's `calc` where wide browser support is not as important (IE8 and below and Safari 5 don't support it). – jeffjenx Apr 20 '14 at 16:53
  • 3
    Any way to do similar with a dynamic `#up` height? – Adam Waite Aug 04 '14 at 13:49
  • @AdamWaite, with a dynamic #up height, you will want to use the overflow solution described in the other answer. – jeffjenx Nov 24 '14 at 18:26
  • 1
    calc should not be used in simple case. It causes unnecessary re-flow with is very resource consuming in browsers. In many cases will also introduce clunky UI behavior since re-flow affects other elements and forces them to re-flow themselves. – twboc May 17 '23 at 10:58
24

Abstract

I didn't find a fully satisfying answer so I had to find it out myself.

My requirements:

  • the element should take exactly the remaining space either when its content size is smaller or bigger than the remaining space size (in the second case scrollbar should be shown);
  • the solution should work when the parent height is computed, and not specified;
  • calc() should not be used as the remaining element shouldn't know anything about another element sizes;
  • modern and familar layout technique such as flexboxes should be used.

The solution

  • Turn into flexboxes all direct parents with computed height (if any) and the next parent whose height is specified;
  • Specify flex-grow: 1 to all direct parents with computed height (if any) and the element so they will take up all remaining space when the element content size is smaller;
  • Specify flex-shrink: 0 to all flex items with fixed height so they won't become smaller when the element content size is bigger than the remaining space size;
  • Specify overflow: hidden to all direct parents with computed height (if any) to disable scrolling and forbid displaying overflow content;
  • Specify overflow: auto to the element to enable scrolling inside it.

JSFiddle (element has direct parents with computed height)

JSFiddle (simple case: no direct parents with computed height)

N. Kudryavtsev
  • 3,556
  • 1
  • 26
  • 30
6

My answer uses only CSS, and it does not use overflow:hidden or display:table-row. It requires that the first child really does have a given height, but in your question you state that only the second child need have its height not specified, so I believe you should find this acceptable.

#container {
  width: 300px;
  height: 300px;
  border: 1px solid red;
}

#up {
  background: green;
  height: 63px;
  float: left;
  width: 100%
}

#down {
  background: pink;
  padding-top: 63px;
  height: 100%;
  box-sizing: border-box;
}
<div id="container">
  <div id="up">Text<br />Text<br />Text<br /></div>
  <div id="down">Text<br />Text<br />Text<br /></div>
</div>
callmenikk
  • 1,358
  • 2
  • 9
  • 24
T.W.R. Cole
  • 4,106
  • 1
  • 19
  • 26
2

Unless I am misunderstanding, you can just add height: 100%; and overflow:hidden; to #down.

#down { 
    background:pink; 
    height:100%; 
    overflow:hidden;
}​

Live DEMO

Edit: Since you do not want to use overflow:hidden;, you can use display: table; for this scenario; however, it is not supported prior to IE 8. (display: table; support)

#container { 
    width: 300px; 
    height: 300px; 
    border:1px solid red;
    display:table;
}

#up { 
    background: green;
    display:table-row;
    height:0; 
}

#down { 
    background:pink;
    display:table-row;
}​

Live DEMO

Note: You have said that you want the #down height to be #container height minus #up height. The display:table; solution does exactly that and this jsfiddle will portray that pretty clearly.

Josh Mein
  • 28,107
  • 15
  • 76
  • 87
  • 1
    I don't want #down to exceed #container height – Alvaro Jun 27 '12 at 12:20
  • I just noticed that. You can add `overflow:hidden` to to hide the extra content. – Josh Mein Jun 27 '12 at 12:22
  • 2
    I'll copy/paste what I said to MrSlayer: I would like #down to have #container height - #up height. So overflow hidden is not what I'm looking for. And also don't want to use absolute position. Thanks! – Alvaro Jun 27 '12 at 12:23
  • The problem with this is that if you revert the two divs in your example then the green div is outside. – Ced Sep 08 '15 at 22:44
  • This does not answer the question at all. It states "To occupy all of the remaining height", event though this occupies all of the remaining height, there will be overflow. – Giridhar Karnik May 25 '16 at 08:00
2

check the demo - http://jsfiddle.net/S8g4E/6/

use css -

#container { width: 300px; height: 300px; border:1px solid red; display: table;}
#up { background: green; display: table-row; }
#down { background:pink; display: table-row;}
thirtydot
  • 224,678
  • 48
  • 389
  • 349
Dipak
  • 11,930
  • 1
  • 30
  • 31
  • You should add `height: 1px` to `#up` to ensure it takes the minimum amount of height. Here's the browser support for `display: table`: http://caniuse.com/css-table – thirtydot Jun 27 '12 at 12:22
  • Could you please show me how can this solution be achieved in this "more complex" example, please: http://jsfiddle.net/fyNX4/ Thank you very much – Alvaro Jun 27 '12 at 12:44
1

You can use floats for pushing content down:

http://jsfiddle.net/S8g4E/5/

You have a fixed size container:

#container {
    width: 300px; height: 300px;
}

Content is allowed to flow next to a float. Unless we set the float to full width:

#up {
    float: left;
    width: 100%;
}

While #up and #down share the top position, #down's content can only start after the bottom of the floated #up:

#down {
    height:100%;
}​
biziclop
  • 14,466
  • 3
  • 49
  • 65
  • Note that `#up` actually covers the top part of `#down`: http://jsfiddle.net/thirtydot/S8g4E/9/ – thirtydot Jun 27 '12 at 12:24
  • Yes, that's how it works. But if OP doesn't need a rounded border or something other fancyness on `#up`, then it is probably acceptable. – biziclop Jun 27 '12 at 12:26
  • This solution is close, but I would like #down to have #container height - #up height. (In your solution #down height = #container height). Thanks' – Alvaro Jun 27 '12 at 12:26
  • 1
    @Alvaro: Why does it need to be like that? This solution *looks* correct in most cases, even if it is only an illusion. – thirtydot Jun 27 '12 at 12:27
  • Well, this question is a simplified example from this more "complex" example: http://jsfiddle.net/fyNX4/ There wouldn't work, no? – Alvaro Jun 27 '12 at 12:36
  • Well, in this case probably the `display:table` solution is the best. – biziclop Jun 27 '12 at 12:40
  • I was trying to implement table solution to the "complex" example, but can't get it to work.. – Alvaro Jun 27 '12 at 12:43
  • Biziclop,That is great! Please could you post this as an answer here: http://stackoverflow.com/questions/11212155/second-child-div-height-fill-parent-height And I'll give you the correct answer. Thanks! – Alvaro Jun 27 '12 at 13:00
  • Hi, I added the `table` solution there :) – biziclop Jun 27 '12 at 13:22
1
<div class='parent'>
  <div class='child'>
  <div class='child last'>
</div>

<style>
.parent {
  display: flex;
  flex-direction: column;

  .child {
     &.last {
        flex-grow: 1;
     }
  }
}
</style>
T.Woody
  • 1,142
  • 2
  • 11
  • 25
-2

I'm not sure it can be done purely with CSS, unless you're comfortable in sort of faking it with illusions. Maybe use Josh Mein's answer, and set #container to overflow:hidden.

For what it's worth, here's a jQuery solution:

var contH = $('#container').height(),
upH = $('#up').height();
$('#down').css('height' , contH - upH);
Jezen Thomas
  • 13,619
  • 6
  • 53
  • 91