HTML5, CSS3: Fixed size box with fluid to panel and rest-size bottom panel

Problem

I've spent ages scouring Google for an answer to my (relatively) simple problem, but haven't been able to find one.

I want to have a box (div?) in our web based business application that has a height of 100% of its parent container. Within that box, there should be 2 boxes, stacked on top of each other.

  • The top box should resize according to its contents. (which will never be more than 50% of the total height).
  • The bottom box should get the rest of the height. Any overflow should scroll.

Preferably no javascript should be used, especially no javascript timers that poll the heights every x milliseconds.

Here's a mockup of the result: Image of Problem

Is there a solution to this issue?

Problem courtesy of: Erik v O.

Solution

SEE THE THIRD EDIT, IT IS THE BEST SOLUTION


I believe something similar to this is as close as you can get (assuming they are structured as I believe they are)

/* HTML */
<div id='container'>
    <div id='top'></div>
    <div id='bottom'></div>
</div>

/* CSS */
#container {
    width:300px; /* I assume the width/height is fixed */
    height:200px;
    border: 1px solid black;
    padding:4px; /* To remove the horiz scrollbar with width:100% and a border */
    overflow:hidden; /* Hide the content at the bottom to allow scroll */
}
#top {
    width:100%;
    max-height:50%; /* Using max-height allows it to size to smaller content */
    overflow:auto; /* Allow a scrollbar if necessary */
}
#bottom {
    height:100%; /* Take up the remaining space */
    overflow:auto; /* Allow a scrollbar if necessary */
}

Demo here

On a side note, your question should include the problem, your code related to the problem, and also your attempts at a solution. That way we can understand exactly what your problem is, see that you've tried a solution yourself, and use your actual code to fix it


Edit

In order to get it exactly as you desire, you could use a little javascript

var parent = document.getElementById('container'),
    top = parent.children[0],
    bottom = parent.children[1];

bottom.style.height =  parent.offsetHeight - top.offsetHeight - 8 + "px";
// The 8 comes from the vertical padding of the parent + 4 (not sure what the 4 
// is from, probably the four vertical padding widths). The actual number could
// be calculated dynamically, but that would require using getComputedStyle and
// is more work than it's worth since borders/padding don't change dynamically

Demo here

If you don't care about formatting then you could do it in one long line by

document.getElementById('bottom').style.height = document.getElementById('container').offsetHeight - document.getElementById('top').offsetHeight - 8 + "px";

Javascript is needed because you cannot set a height based on another element's variable height in pure CSS like you hope to. For more info on offsetHeight, look here


Second Edit

If you have to make it respond to input (I used contenteditable) you can use the onclick and onkeyup events to bind the function to it. You should have all the tools you need to make it the way you want it now, it is impossible for me to know exactly what you want or how you want it to behave

top.onkeyup = function() {
    bottom.style.height =  parent.offsetHeight - top.offsetHeight - 8 + "px";
}
top.onkeyup();
top.onclick = function() {
    top.onkeyup();
}

Demo here


Third Edit

Not sure why I didn't think about this before, but this is a perfect situation for flexbox. It's simpler, more intuitive, and easier to manipulate. P.S. I included browser prefixes in the demo

#container {
    ...
    overflow:hidden; /* Hide overflow */
    /* I excluded vendor prefixes for the sake of brevity, they're in the demo */
    flex-flow: column; /* Makes content flow down instead of across */    
    display: flex;
}
#top {
    ...
    max-height:50%; /* Sets the max height... */
    overflow:auto; /* Make sure scrollbar is there */        
    box-flex: none;
    flex: none; /* In essence, this acts like `height:auto` */
}
#bottom {
    ...
    border:1px solid red;
    overflow:auto; /* Make sure scrollbar is there */        
    flex: 2; /* Can be any positive number in this case */
}

Awesome CSS only demo here. For more information on flexbox, check out this article, this video series and post, and also some examples. However, the best way to learn it is to try projects yourself in my view

Solution courtesy of: Zach Saucier

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.