89

From my research, this appears to be an absolutely classic CSS question, but I can't find a definitive answer - so StackOverflow it is.

How do I set a content div to take up 100% of the body height, minus the height taken up by a fixed-height header and footer?

<body>
  <header>title etc</header>
  <div id="content">body content</div>
  <footer>copyright etc</footer>
</body>

//CSS
html, body { 
  height: 100%;
}
header { 
  height: 50px;
}
footer { 
  height: 50px;
}
#content { 
  height: 100% of the body height, minus header & footer
}

I would like to use pure CSS, and for the answer to be bulletproof across browsers.

SierraOscar
  • 17,507
  • 6
  • 40
  • 68
Richard
  • 62,943
  • 126
  • 334
  • 542

8 Answers8

66

this version will work in all the latest browsers and ie8 if you have the modernizr script (if not just change header and footer into divs):

Fiddle

html,
body {
  min-height: 100%;
  padding: 0;
  margin: 0;
}

#wrapper {
  padding: 50px 0;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

#content {
  min-height: 100%;
  background-color: green;
}

header {
  margin-top: -50px;
  height: 50px;
  background-color: red;
}

footer {
  margin-bottom: -50px;
  height: 50px;
  background-color: red;
}

p {
  margin: 0;
  padding: 0 0 1em 0;
}
<div id="wrapper">
  <header>dfs</header>
  <div id="content">
  </div>
  <footer>sdf</footer>
</div>

Scrolling with content: Fiddle

dippas
  • 58,591
  • 15
  • 114
  • 126
Pete
  • 57,112
  • 28
  • 117
  • 166
  • 1
    As this answer seems to be being hit a lot I thought I should also give [a link to this answer as it has some alternatives](http://stackoverflow.com/questions/23651942/css-single-column-layout-centered-fixed-width-100-height-w-header-and-footer/23657083#23657083) – Pete Nov 28 '14 at 12:35
  • 1
    Running the jsfiddle demo makes the header and footer scroll. From the question, I understand that the requirement is to have the header/footer shown even when the content is scrollable. – AlikElzin-kilaka Oct 22 '15 at 14:37
  • 1
    @AlikElzin-kilaka did you read the comments too? I asked the questions that lead me to this answer which was accepted over 2 years ago – Pete Oct 22 '15 at 14:56
  • @AlikElzin-kilaka Besides as this question is so old, it is pretty out of date and I would go with using display flex now as the support for that is now all major browsers, where as when this was answered, flex had quite limited support – Pete Oct 22 '15 at 15:01
  • Definitively that is not an answer event 2 years ago.... what is the point of having fixed divs thats scrolls when the content have to have to be scrolled. – ElLocoCocoLoco Oct 29 '15 at 15:14
40

As far as it is not cross browser solution, you might be take advantage of using calc(expression) to achive that.

html, body { 
 height: 100%;
}
header {        
 height: 50px;
 background-color: tomato
}

#content { 
 height: -moz-calc(100% - 100px); /* Firefox */
 height: -webkit-calc(100% - 100px); /* Chrome, Safari */
 height: calc(100% - 100px); /* IE9+ and future browsers */
 background-color: yellow 
}
footer { 
 height: 50px;
 background-color: grey;
}

Example at JsFiddle

If you want to know more about calc(expression) you'd better to visit this site.

Community
  • 1
  • 1
agriboz
  • 4,724
  • 4
  • 35
  • 49
  • 1
    I wanted to just mention something for this solution. when using calc with height, it will be the calculated height of that element when the page loads. if your content container expands from loading some dynamic content, the overflow will be visible, which is fine, but if you are wanting to set a background color on the #content element, make it min-height instead of height so it will always expand content correctly. – Kelly Milligan Nov 03 '15 at 14:45
31

This still came up as the top Google result when I was trying to find an answer to this question. I didn't have to support older browsers in my project and I feel like I found a better, simpler solution in flex-box. The CSS snippet below is all that is necessary.

I have also shown how to make the main content scrollable if the screen height is too small.

html,
body {
  height: 100%;
  display: flex;
  flex-direction: column;
}
header {
  min-height: 60px;
}
main {
  flex-grow: 1;
  overflow: auto;
}
footer {
  min-height: 30px;
}
<body style="margin: 0px; font-family: Helvetica; font-size: 18px;">
  <header style="background-color: lightsteelblue; padding: 2px;">Hello</header>
  <main style="overflow: auto; background-color: lightgrey; padding: 2px;">
    <article style="height: 400px;">
      Goodbye
    </article>
  </main>
  <footer style="background-color: lightsteelblue; padding: 2px;">I don't know why you say, "Goodbye"; I say, "Hello."</footer>
</body>
Marko Bonaci
  • 5,622
  • 2
  • 34
  • 55
Matt L
  • 686
  • 9
  • 12
  • Oh yeah, as if "flex", "flex-grow", and "flex-direction" -- names that open a whole black box full of behavior -- is more clear than a simple vertical offset. I'll stick with the negative margins. – Triynko Oct 12 '15 at 05:58
  • @Triynko, I agree that using negative margins is a fine solution, but it didn't fit my needs. The solution I provided has the advantage of always having the header and footer shown on the page and the rest of the content filling the screen and being scrollable. – Matt L Oct 14 '15 at 20:48
  • 5
    This is the method of the future. No need to know the exact height of your header/footer either. Percentages are now possible. – Simon East Dec 08 '15 at 06:36
  • 2
    Currently most browsers support flex. I think I'll go with this solution. Due to responsiveness this seems the best solution – GorillaApe Sep 07 '16 at 07:12
  • The `main` element in my app is extending beyond the footer and scrolling when the content height is much smaller than the `main` element. I see that the snippet is able to render the `main` element with a height that fills the viewport without scrolling. Are there any pointers on debugging a flexbox that isn't sizing the elements as expected? – John May 03 '20 at 18:47
  • 1
    @John, Without being able to see what you have it's difficult to know for sure. For flexbox elements that are not sizing as expected I would scrutinize the flex-basis, flex-grow, and flex-shrink properties -- or just flex, which can incorporate all 3 -- on the child element which is not the expected size, your main in this case. I included this above, but I'll include it again here, CSS-Tricks' Complete Guide To Flexbox is a Godsend. https://css-tricks.com/snippets/css/a-guide-to-flexbox/ Still having trouble? Re-create the bare minimum in Codepen and post a link. https://codepen.io/pen/ – Matt L May 05 '20 at 14:17
18

The new, modern way to do this is to calculate the vertical height by subtracting the height of both the header and the footer from the vertical-height of the viewport.

//CSS
header { 
  height: 50px;
}
footer { 
  height: 50px;
}
#content { 
  height: calc(100vh - 50px - 50px);
}
Eric Warnke
  • 1,325
  • 12
  • 18
2

Trying to calculate the header and footer is bad :( A design should be simple, self explanatory. Plain easy. Calculations are just...not easy. Not easy for human and a bit hard on machines.

What you're looking for is a subset of the Holy Grail design.

Here's an implementation using the flex display. It includes side bars in addition to the footer and header. Enjoy:

<!DOCTYPE html>
<html style="height: 100%">
  <head>
    <meta charset=utf-8 />
    <title>Holy Grail</title>
    <!-- Reset browser defaults -->
    <link rel="stylesheet" href="reset.css">
  </head>
  <body style="display: flex; height: 100%; flex-direction: column">
    <div>HEADER<br/>------------
    </div>
    <!-- No need for 'flex-direction: row' because it's the default value -->
    <div style="display: flex; flex: 1">
      <div>NAV|</div>
      <div style="flex: 1; overflow: auto">
        CONTENT - START<br/>
        <script>
        for (var i=0 ; i<1000 ; ++i) {
          document.write(" Very long content!");
        }
        </script>
        <br/>CONTENT - END
      </div>
      <div>|SIDE</div>
    </div>
    <div>------------<br/>FOOTER</div>
  </body>
</html>
AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277
0

You can take advatange of the css property Box Sizing.

#content { 
    height: 100%;
    -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
    -moz-box-sizing: border-box;    /* Firefox, other Gecko */
    box-sizing: border-box;         /* Opera/IE 8+ */
    padding-top: 50px;
    margin-top: -50px;
    padding-bottom: 50px;
    margin-bottom: -50px;
}

See the JsFiddle.

  • Thanks, but this doesn't work with lots of body content: http://jsfiddle.net/8Hqm5/1/ I think @Pete's solution is better for handling cases where the size of the body content is unknown. – Richard Feb 22 '13 at 13:06
0

This question has been pretty well answered, but I'm taking the liberty of adding a javascript solution. Just give the element that you want to 'expand' the id footerspacerdiv, and this javascript snippet will expand that div until the page takes up the full height of the browser window.

It works based on the observation that, when a page is less than the full height of the browser window, document.body.scrollHeight is equal to document.body.clientHeight. The while loop increases the height of footerspacerdiv until document.body.scrollHeight is greater than document.body.clientHeight. At this point, footerspacerdiv will actually be 1 pixel too tall, and the browser will show a vertical scroll bar. So, the last line of the script reduces the height of footerspacerdiv by one pixel to make the page height exactly the height of the browser window.

By placing footerspacerdiv just above the 'footer' of the page, this script can be used to 'push the footer down' to the bottom of the page, so that on short pages, the footer is flush with the bottom of the browser window.

<script>    
//expand footerspacer div so that footer goes to bottom of page on short pages        
  var objSpacerDiv=document.getElementById('footerspacer');          
  var bresize=0;   

  while(document.body.scrollHeight<=document.body.clientHeight) {
    objSpacerDiv.style.height=(objSpacerDiv.clientHeight+1)+"px";
    bresize=1;
  }             
  if(bresize) { objSpacerDiv.style.height=(objSpacerDiv.clientHeight-1)+"px"; }               
 </script>
mti2935
  • 11,465
  • 3
  • 29
  • 33
0

Here's a solution that doesn't use negative margins or calc. Run the snippet below to see the final result.

Explanation

We give the header and the footer a fixed height of 30px and position them absolutely at the top and bottom, respectively. To prevent the content from falling underneath, we use two classes: below-header and above-footer to pad the div above and below with 30px.

All of the content is wrapped in a position: relative div so that the header and footer are at the top/bottom of the content and not the window.

We use the classes fit-to-parent and min-fit-to-parent to make the content fill out the page. This gives us a sticky footer which is at least as low as the window, but hidden if the content is longer than the window.

Inside the header and footer, we use the display: table and display: table-cell styles to give the header and footer some vertical padding without disrupting the shrink-wrap quality of the page. (Giving them real padding can cause the total height of the page to be more than 100%, which causes a scroll bar to appear when it isn't really needed.)

.fit-parent {
    height: 100%;
    margin: 0;
    padding: 0;
}
.min-fit-parent {
    min-height: 100%;
    margin: 0;
    padding: 0;
}
.below-header {
    padding-top: 30px;
}
.above-footer {
    padding-bottom: 30px;
}
.header {
    position: absolute;
    top: 0;
    height: 30px;
    width: 100%;
}
.footer {
    position: absolute;
    bottom: 0;
    height: 30px;
    width: 100%;
}

/* helper classes */

.padding-lr-small {
    padding: 0 5px;
}
.relative {
    position: relative;
}
.auto-scroll {
  overflow: auto;
}
/* these two classes work together to create vertical centering */
.valign-outer {
    display: table;
}
.valign-inner {
    display: table-cell;
    vertical-align: middle;
}
<html class='fit-parent'>
  <body class='fit-parent'>
<div class='min-fit-parent auto-scroll relative' style='background-color: lightblue'>
<div class='header valign-outer' style='background-color: black; color: white;'>
        <div class='valign-inner padding-lr-small'>
            My webpage
        </div>
    </div>
    <div class='fit-parent above-footer below-header'>
        <div class='fit-parent' id='main-inner'>
          Lorem ipsum doloris finding dory Lorem ipsum doloris finding
          dory Lorem ipsum doloris finding dory Lorem ipsum doloris
          finding dory Lorem ipsum doloris finding dory Lorem ipsum
          doloris finding dory Lorem ipsum doloris finding dory Lorem
          ipsum doloris finding dory Lorem ipsum doloris finding dory
          Lorem ipsum doloris finding dory Lorem ipsum doloris finding
          dory Lorem ipsum doloris finding dory Lorem ipsum doloris
          finding dory Lorem ipsum doloris finding dory Lorem ipsum
          doloris finding dory Lorem ipsum doloris finding dory Lorem
          ipsum doloris finding dory Lorem ipsum doloris finding dory
          Lorem ipsum doloris finding dory Lorem ipsum doloris finding
          dory Lorem ipsum doloris finding dory Lorem ipsum doloris
          finding dory Lorem ipsum doloris finding dory Lorem ipsum
          doloris finding dory Lorem ipsum doloris finding dory Lorem
          ipsum doloris finding dory Lorem ipsum doloris finding dory
          Lorem ipsum doloris finding dory Lorem ipsum doloris finding
          dory Lorem ipsum doloris finding dory Lorem ipsum doloris
          finding dory Lorem ipsum doloris finding dory Lorem ipsum
          doloris finding dory Lorem ipsum doloris finding dory Lorem
          ipsum doloris finding dory Lorem ipsum doloris finding dory
          Lorem ipsum doloris finding dory Lorem ipsum doloris finding
          dory Lorem ipsum doloris finding dory Lorem ipsum doloris
          finding dory Lorem ipsum doloris finding dory Lorem ipsum
          doloris finding dory Lorem ipsum doloris finding dory Lorem
          ipsum doloris finding dory Lorem ipsum doloris finding dory
          Lorem ipsum doloris finding dory Lorem ipsum doloris finding
          dory Lorem ipsum doloris finding dory Lorem ipsum doloris
          finding dory Lorem ipsum doloris finding dory Lorem ipsum
          doloris finding dory Lorem ipsum doloris finding dory Lorem
          ipsum doloris finding dory Lorem ipsum doloris finding dory
          Lorem ipsum doloris finding dory Lorem ipsum doloris finding
          dory Lorem ipsum doloris finding dory Lorem ipsum doloris
          finding dory Lorem ipsum doloris finding dory Lorem ipsum
          doloris finding dory Lorem ipsum doloris finding dory Lorem
          ipsum doloris finding dory Lorem ipsum doloris finding dory
        </div>
    </div>
    <div class='footer valign-outer' style='background-color: white'>
        <div class='valign-inner padding-lr-small'>
            &copy; 2005 Old Web Design
        </div>
    </div>
</div>
    </body>
  </html>
Chris Middleton
  • 5,654
  • 5
  • 31
  • 68