Flexible DIV to cover the rest of the page and divide the height in half for children

Here’s a sample layout:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>Dynamic DIV</title>
    <style>
        #header {
            background: green;
        }
        #header * {
            vertical-align: middle;
        }
        button {
            float: right;
        }
        #top {
            background: yellow;
        }
        #bottom {
            background: aqua;
        }
    </style>
</head>

<body>
    <div id="header">
        <label for="checker">Check</label>
        <input type="checkbox" id="checker">
        <label for="slider">Slider</label>
        <input type="range" id="slider"><span>Some text</span>
        <button type="button">Bar</button>
        <button type="button">Foo</button>
    </div>
    <div id="content">
        <div id="top">Top content</div>
        <div id="bottom">Bottom content</div>
    </div>
</body>

</html>

Demo: http://jsfiddle.net/CZt36/1/

How can I extend the content DIV to he rest of the page so that the top and bottom DIVs get 50% of the content DIV height?

Normally we encourage folks to let the content dictate the height of the page except for a sticky footer perhaps. A couple of questions…

Is the page expected to be responsive or fluid or will this be a fixed width page?

Is the height of the page expected to extend longer than the height of the viewport or will the content be entirely visible in the window?

Fluid: 100%.

Is the height of the page expected to extend longer than the height of the viewport or will the content be entirely visible in the window?

The content will be entirely visible in the window with no scrollbars.
No matter what screen resolution you use, the page should cover the viewport completely.

Give this a try and see if it is something you can use.

The height of the header box is fixed at 40px.

The heights of #top and #bottom are 50% of the remaining screen height, as requested.

Vertical scrollbars will be generated if content tries to extend any of those 3 containers. That means that only a limited amount of content is permitted and it should be equally distributed between #top and #bottom, OR the percentages of those two containers can be changed to whatever ratio is needed as long as they total 100%.

This is not truly fluid in that the ratio of the heights of the boxes is not adaptable; however, you can use media queries when necessary to adjust the heights of the header and content boxes as needed.


<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Dynamic DIV</title>
    <style>
body {
    padding:0;
    margin:0;
}
*, *:before, *:after {
    -webkit-box-sizing:border-box;
    -moz-box-sizing:border-box;
    box-sizing:border-box;
}
#header {
    display:table;
    width:100%;
    height:40px;
    background:green;
}
.tcell {
    display:table-cell;
    vertical-align:middle;
}
#header * {
    vertical-align:middle;
}
button {
    float:right;
}
#content {
    position:absolute;
    top:40px;  /* same value as height of header */
    left:0;
    right:0;
    bottom:0;
}
#top,
#bottom {
    position:absolute;
    height:50%;
    width:100%;
}
#top {
    background:yellow;
    top:0;
}
#bottom {
    background:aqua;
    bottom:0;
}
    </style>
</head>
<body>

<div id="header">
    <div class="tcell">
    <button type="button">Bar</button>
    <button type="button">Foo</button>
    <label for="checker">Check</label>
    <input type="checkbox" id="checker">
    <label for="slider">Slider</label>
    <input type="range" id="slider">
    <span>Some text</span>
    </div>
</div>
<div id="content">
    <div id="top">Top content</div>
    <div id="bottom">Bottom content</div>
</div>

</body>
</html>

Thanks for the answer! :slight_smile:
The header height changes from browser to browser unless we give it a larger fixed height as you did. But I want it to take up exactly the space it needs in any browser – no more. Any approach without giving a fixed height to the header?

You can do it with flexbox for modern browsers only.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<style>
html, body {
	margin:0;
	padding:0
}
body {
	display: flex;
	height: 100vh;
	flex-direction: column;
}
.content {
	flex: 1;
	overflow:auto
}
header { background:orange }
main.content { background:blue }
footer { background:red }
</style>
</head>

<body>
<header>
		<button type="button">Bar</button>
		<button type="button">Foo</button>
		<label for="checker">Check</label>
		<input type="checkbox" id="checker">
		<label for="slider">Slider</label>
		<input type="range" id="slider">
		<span>Some text</span> </header>
<main class="content">test</main>
<footer  class="content">test</footer>
</body>
</html>

Here’s a screenshot showing the header height in IE11:

The image is pending approval.

I turned on my Win7 box and opened the file in IE11. The header looks really crummy. Not horizontally aligned well at all. I’ll give it another go and see if I can improve that.

You need to take the default margin and padding out of the mix for IE11.


#header * { vertical-align:middle;margin:0;padding:0 }

I just learned about the default padding :rolleyes: and was about to post just what you said, ninja Paul. :slight_smile:

You might want to set #header * {padding:0 auto;} to preserve the horizontal padding in the buttons,
and add to the button {margin-left:10px;} to separate them a tad.

Regarding the header height in the screen shot in post #7, it looks taller than 40px.

Off Topic:

@Paul_O_B would you mind explaining how the flex-box example works? That is amazing stuff.

Does this not kill default padding in form controls for other browsers though? The kind you can’t add back in?

Kudos for the main in the code :stuck_out_tongue:

Question on flexbox: if using flexbox and browsers don’t know elements like <main> and <footer>, does flexbox just create their block-context or do you actually still have to display: block them for someone?

Browsers have changed a bit these days and the arguments for not removing padding and margins are not quite the same as they were. You may lose some visual clues such as the depress effect on submit buttons but you can replace this with other focus styles. I find it better to explicitly control the padding, margin and line-height on form elements these days for better results and I also use the border-box model for IE8 plus so that textareas and selects are the same widths as inputs.

Whatever method you use there will always be a discrepancy so it’s a matter of being careful and checking the results :slight_smile:

Kudos for the main in the code :stuck_out_tongue:

Question on flexbox: if using flexbox and browsers don’t know elements like <main> and <footer>, does flexbox just create their block-context or do you actually still have to display: block them for someone?

I usually set them to block in the default reset although modern browsers should know about them now (maybe not ‘main’ yet though) so yes if you had no ‘reset’ styles then the element should be set to block just in case when using flex.

@Paul O’B would you mind explaining how the flex-box example works? That is amazing stuff.

I’m just getting my head around it also but the basis of the demo was that the 100vh sets the element to 100% of the viewport height and the flex-direction: column; sets the child boxes to be stacked vertically rather than horizontally.

The flex:1 on two of the children says that you want the space ratio that they occupy to be the same so the rest of the space in that element is evenly divided between those two items. If one was flex 2 then it would have twice the space as the other one and so on. The item without the flex1 just takes up its own space as required.

It makes the sticky footer pretty easy as you can do the same sort of thing.

Some demos here:

http://www.sketchingwithcss.com/flexbox/
http://www.sketchingwithcss.com/flex-container/

The main problem is browsers support so it will be a couple of years before we can go mainstream with it without a fall-back.

Here is a javascript method of doing the job (some CSS too :slight_smile: ). I have attached the background image to this post. The script works in all browsers back to IE7. It makes use of the mousemove event to change the position of a slider block inside a div. The percentage position of the slider is used to set the height of the outer container. The top and bottom content are set at 50% of the container height. The fully collapsed state has been constrained to 40px to allow the content text to be readable.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Dynamic DIV</title>
<script type="text/javascript">
 function show_coords(evt)
   { var elem, coords, heightVal;
     elem=(evt.target)? evt.target : evt.srcElement;
     coords={left:0, top:0};
     if(evt.layerX)
      { coords.left=evt.layerX; coords.top=evt.layerY; }
     else if(evt.offsetX)
      { coords.left=evt.offsetX+1; coords.top=evt.offsetY+1; }
     evt.cancelBubble=true;
    //
     var slidePosn=coords.left-5;   // allow for half width of slider block
     holderObj.style.backgroundPosition=slidePosn+"px","0px";
     var indx=coords.left/parseInt(slideWidth)*100;
     indx=(indx>=100)?100 :((indx<=0)? 0 :indx);
     outputObj.value="percent: " + parseInt(indx);
     heightVal=parseInt(contentHeight*indx/100);
     heightVal=(heightVal<=40)? 30 : heightVal;
     contentObj.style.height=heightVal+"px";
   }
// -----------
 var contentObj, outputObj, contentHeight, slideWidth; // global
 function init()
  { contentObj=document.getElementById("content")
    contentHeight=400;                                 // height of outer container
    contentObj.style.height=contentHeight+"px";
    outputObj=document.getElementById("output");
    outputObj.value="Move slider";
    holderObj=document.getElementById("holder");
    slideWidth=holderObj.style.width="200px";          // set width of slider
    holderObj.style.backgroundPosition=(parseInt(slideWidth)/2)-10+"px",0+"px"; // initial posn of slider block
  }
</script>
<style type="text/css">
body   { font-family:arial, helvetica, sans-serif; font-weight:normal; font-size:16px; color:#000; font-weight:bold; text-align:left; margin:3px 0px; }
#wrap  { width:500px; height:500px; margin-left:20px; }
#header { position:relative; top:0px; left:0px; height:120px; background-color: green; overflow:auto; }
#content { height:400px; margin-top:5px;  }
#top    { height:50%; background-color: #FF0; padding:2px; }
#bottom { height:50%; background-color: #0FF; padding:2px; }
#holder { position:relative; top:0px; left:0px; border:1px solid white; width:200px; height:20px; margin-left:10px; cursor:pointer;  }
/* note:   background image block1.jpg reqd. size 10x20px         */
#holder { background-color:#444; background-image:url('block1.jpg'); background-repeat:no-repeat; background-position:0px,0px; }
#output { margin:10px;  }
.a14B   { font-size:14px; font-weight:bold; color:#FFF; margin:10px; }
</style>
</head>

<body>

<div id="wrap">
  <div id="header">
    <p class="a14B">Slide block to set height of content</p>
    <div id="holder" onmousemove="show_coords(event)">
    </div>
    <input id="output" type="text" value size="10" readonly>
  </div>
  <div id="content">
    <div id="top">
      Top content</div>
    <div id="bottom">
      Bottom content</div>
  </div>
</div>
<script type="text/javascript">
   window.onload=init;
 </script>

</body>

</html>


I’m working on a CSS solution.
Thanks for the code anyway! :slight_smile:

Nice demo :slight_smile:

Many thanks for the answer! I’ve been busy doing some tests and playing around with ronpat’s solution.
I need to study flexbox before I use your code and will come back if I have more questions.

Thanks again! :slight_smile:

The only trouble maker is input type=range and removing its top and bottom padding seems to be enough to resolve the issue:

input[type="range"] {padding-top:0; padding-bottom:0;}

Internet Explorer is too stupid to understand it. We should either remove the padding completely, as Paul mentioned:

input[type="range"] {padding:0;}

or top and bottom padding:

input[type="range"] {padding-top:0; padding-bottom:0;}

Regarding the header height in the screen shot in post #7, it looks taller than 40px.

60px, to be more accurate.

I tested {padding:0 auto;} using IE11 before I posted that note and it seemed to work fine. However, being more specific like you did you can’t go wrong. Thanks for the feedback :slight_smile:

Paul’s flexbox solution is exciting! I’m reading up on it, too! Very neat stuff.

It seems like a bug in Chrome: 100vh doesn’t stretch the page in zoom/F11. Here’s the page I tried.