Search code examples
htmlcsshtml-table

Make a div fill the height of the remaining screen space


I am working on a web application where I want the content to fill the height of the entire screen.

The page has a header, which contains a logo, and account information. This could be an arbitrary height. I want the content div to fill the rest of the page to the bottom.

I have a header div and a content div. At the moment I am using a table for the layout like so:

CSS and HTML

#page {
  height: 100%;
  width: 100%
}

#tdcontent {
  height: 100%;
}

#content {
  overflow: auto;  /* or overflow: hidden; */
}
<table id="page">
  <tr>
    <td id="tdheader">
      <div id="header">...</div>
    </td>
  </tr>
  <tr>
    <td id="tdcontent">
      <div id="content">...</div>
    </td>
  </tr>
</table>

The entire height of the page is filled, and no scrolling is required.

For anything inside the content div, setting top: 0; will put it right underneath the header. Sometimes the content will be a real table, with its height set to 100%. Putting header inside content will not allow this to work.

Is there a way to achieve the same effect without using the table?

Update:

Elements inside the content div will have heights set to percentages as well. So something at 100% inside the div will fill it to the bottom. As will two elements at 50%.

Update 2:

For instance, if the header takes up 20% of the screen's height, a table specified at 50% inside #content would take up 40% of the screen space. So far, wrapping the entire thing in a table is the only thing that works.


Solution

  • 2015 update: the flexbox approach

    There are two other answers briefly mentioning flexbox; however, that was more than two years ago, and they don't provide any examples. The specification for flexbox has definitely settled now.

    Note: Though CSS Flexible Boxes Layout specification is at the Candidate Recommendation stage, not all browsers have implemented it. WebKit implementation must be prefixed with -webkit-; Internet Explorer implements an old version of the spec, prefixed with -ms-; Opera 12.10 implements the latest version of the spec, unprefixed. See the compatibility table on each property for an up-to-date compatibility status.

    (taken from https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes)

    All major browsers and IE11+ support Flexbox. For IE 10 or older, you can use the FlexieJS shim.

    To check current support you can also see here: http://caniuse.com/#feat=flexbox

    Working example

    With flexbox you can easily switch between any of your rows or columns either having fixed dimensions, content-sized dimensions or remaining-space dimensions. In my example I have set the header to snap to its content (as per the OPs question), I've added a footer to show how to add a fixed-height region and then set the content area to fill up the remaining space.

    html,
    body {
      height: 100%;
      margin: 0;
    }
    
    .box {
      display: flex;
      flex-flow: column;
      height: 100%;
    }
    
    .box .row {
      border: 1px dotted grey;
    }
    
    .box .row.header {
      flex: 0 1 auto;
      /* The above is shorthand for:
      flex-grow: 0,
      flex-shrink: 1,
      flex-basis: auto
      */
    }
    
    .box .row.content {
      flex: 1 1 auto;
    }
    
    .box .row.footer {
      flex: 0 1 40px;
    }
    <!-- Obviously, you could use HTML5 tags like `header`, `footer` and `section` -->
    
    <div class="box">
      <div class="row header">
        <p><b>header</b>
          <br />
          <br />(sized to content)</p>
      </div>
      <div class="row content">
        <p>
          <b>content</b>
          (fills remaining space)
        </p>
      </div>
      <div class="row footer">
        <p><b>footer</b> (fixed height)</p>
      </div>
    </div>

    In the CSS above, the flex property shorthands the flex-grow, flex-shrink, and flex-basis properties to establish the flexibility of the flex items. Mozilla has a good introduction to the flexible boxes model.