tags:

views:

878

answers:

1

What I need is a div with pixel-based height containing 3 rows. The top row has variable height depending on the contents. The bottom row has a fixed height. The middle row fills any remaining space. Everything is width 100%.

I've been struggling with constructing a div and CSS-based layout for hours that takes me literally seconds to do using a table. I've tried many approaches including negative bottom margins, nesting divs, various positionings, height settings, display:table, nothing gets me what I need. I've searched this site and the internet, refreshed my memory of the various approaches for liquid layouts. No avail.

I'm not especially worried about compatibility with "old" browsers like IE6 (this app isn't for "public" use). Just getting this to work in IE8+FF+Chrome would be great.

I've stripped the problem to a bare example posted below, along with the table-based layout showing what I want. Sidenote: I love CSS and table-less layout, but, sometimes it just seems ridiculous the lengths we have to go through to make it work.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<style type="text/css">
.container {width:500px;height:200px;border:1px solid black;background-color:#c0c0c0;position:relative;}

/* Styles for colors */
#top td, .top {width:100%;background-color:pink;}
#mid td, .mid {width:100%;background-color:lightgreen;border:1px solid red;}
#bot td, .bot {width:100%;background-color:lightblue;}

/* Styles for Table-based Layout */
#layout {width:100%;height:100%;border-collapse:collapse;}
#layout td {vertical-align:top;padding:0px;}
#top td {}
#mid td {height:100%;}
#bot td {height:2em;}

/* Styles for Table-less Layout */
.top {}
.mid {}
.bot {height:2em;position:absolute;bottom:0px;}

</style>
</head>
<body>

Layout I want (with tables):
<div class="container">
  <table id="layout">
    <tr id="top"><td>Top:<br/>Content-based<br/>Height</td></tr>
    <tr id="mid"><td>Middle:<br/>Fill remaining space</td></tr>
    <tr id="bot"><td>Bottom: Fixed Height</td></tr>
  </table>
</div>

<hr/>

Best I can get with CSS:
<div class="container">
  <div class="top">Top:<br/>Content-based<br/>Height</div>
  <div class="mid">Middle:<br/>Fill remaining space</div>
  <div class="bot">Bottom: Fixed Height</div>
</div>

</body>
</html>

Meanwhile, I couldn't let this stop my progress, spent too much time already. I'm going ahead with the table layout in my project. It's simple and fully satisfies the requirements, even if the purists are wailing somewhere.

Thanks for any suggestions though - I'm mainly curious what the "right" solution is at this point, I hate being stumped. Surely, it's doable?

+4  A: 

The key to your problem is looking at the problem differently -- if you Google "sticky footer" you'll find solutions like the following:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<style type="text/css">
.container {width:500px;height:200px;border:1px solid black;background-color:#c0c0c0;position:relative;}

.notbottom2 {
    min-height: 100%; background-color:lightgreen; width: 100%;
    height: auto !important;
    height: 100%;
}

.mid2 {padding-bottom: 2em;}
.top2 { width: 100%;  background-color: pink;}
.bottom2 { height: 2em; width: 100%; margin-top: -2em; background-color: lightblue; }

</style>
</head>
<body>
<div class="container">
<div class="notbottom2">
    <div class="top2">Top:<br/>Content-based<br/>Height</div>
    <div class="mid2">Middle:<br/>Fill remaining space</div>
</div>
<div class="bottom2">Bottom: Fixed Height</div>
</div>
</body>
</html>

EDIT: there, this should be what you want, more or less.

Walter Mundt
Yup. The minute I saw "the bottom row has a fixed height", my brain went "sticky footer! sticky footer!" :) Btw, if IE6 does turn out to be an issue, you can use #container {min-height:100%;position:relative;} and use a conditional comment to send #container {height:100%;} to IE6 and below.
Martha
the height: auto !important; height: 100%; is an alternate hack for the same purpose. IE6 doesn't get "!important" so the 100% overrides. Other browsers which understand min-height also understand !important so the default "auto" value prevails.
Walter Mundt
First of all, thank you for the quick responses! This still doesn't quite get what I need. Specifically, the requirement "The middle row fills any remaining space". If you add "border:3px solid red;" to your mid2 class, I think you'll see what I mean. I'm looking for a solution where the middle div (Walter's div.mid2) has a height that fills the space in the middle. Hope that makes sense?
Joe Tan
Yeah, makes sense. Unfortunately, I don't think CSS box model has a "fill remaining height" options. Percentage height settings are based on the TOTAL height of the parent. See http://stackoverflow.com/questions/90178/make-a-div-fill-the-remaining-screen-space which suggests a JavaScript-based solution -- i.e. calculate the precise appropriate height for the "middle" area in JS and set it on page load.
Walter Mundt