Sticky header and footer scrollable content

I'm trying to create a page which contains three divs: a header, a footer, and a content area. These should take up 100% of the screen.

The header and footer are small and won't change, the content area could be any size, so I have added overflow:auto to make it scroll when it gets too large.

The problem is, it overflows the height of the screen. I have created a fiddle to demonstrate: https://jsfiddle.net/tdxn1e7p/

I'm using the following CSS to set up the html and body height, so the height:100% trick on the container will work:

html, 
body {
    height: 100%;
}

The structure of my document is:

<div style="height:100%;">
  <div>
    Header content
  </div>
  <div style="overflow:auto;">
    Body content... this could be very long
  </div>
  <div>
    Footer content
  </div>
</div>

I have found a lot of variations on this sort of problem such as this question, but haven't been able to make any of the answers work for me.


Approach 1 - flexbox

It works great for both known and unknown height elements. Make sure to set the outer div to height: 100%; and reset the default margin on body. See the browser support tables.

jsFiddle

html, body {
  height: 100%;
  margin: 0;
}
.wrapper {
  height: 100%;
  display: flex;
  flex-direction: column;
}
.header, .footer {
  background: silver;
}
.content {
  flex: 1;
  overflow: auto;
  background: pink;
}
<div class="wrapper">
  <div class="header">Header</div>
  <div class="content">
    <div style="height:1000px;">Content</div>
  </div>
  <div class="footer">Footer</div>
</div>

Approach 2 - CSS table

For both known and unknown height elements. It also works in legacy browsers including IE8.

jsFiddle

html, body {
  height: 100%;
  margin: 0;
}
.wrapper {
  height: 100%;
  width: 100%;
  display: table;
}
.header, .content, .footer {
  display: table-row;
}
.header, .footer {
  background: silver;
}
.inner {
  display: table-cell;
}
.content .inner {
  height: 100%;
  position: relative;
  background: pink;
}
.scrollable {
  position: absolute;
  left: 0; right: 0;
  top: 0; bottom: 0;
  overflow: auto;
}
<div class="wrapper">
  <div class="header">
    <div class="inner">Header</div>
  </div>
  <div class="content">
    <div class="inner">
      <div class="scrollable">
        <div style="height:1000px;">Content</div>
      </div>
    </div>
  </div>
  <div class="footer">
    <div class="inner">Footer</div>
  </div>
</div>

Approach 3 - calc()

If header and footer are fixed height, you can use CSS calc().

jsFiddle

html, body {
  height: 100%;
  margin: 0;
}
.wrapper {
  height: 100%;
}
.header, .footer {
  height: 50px;
  background: silver;
}
.content {
  height: calc(100% - 100px);
  overflow: auto;
  background: pink;
}
<div class="wrapper">
  <div class="header">Header</div>
  <div class="content">
    <div style="height:1000px;">Content</div>
  </div>
  <div class="footer">Footer</div>
</div>

Approach 4 - % for all

If the header and footer are known height, and they are also percentage you can just do the simple math making them together of 100% height.

html, body {
  height: 100%;
  margin: 0;
}
.wrapper {
  height: 100%;
}
.header, .footer {
  height: 10%;
  background: silver;
}
.content {
  height: 80%;
  overflow: auto;
  background: pink;
}
<div class="wrapper">
  <div class="header">Header</div>
  <div class="content">
    <div style="height:1000px;">Content</div>
  </div>
  <div class="footer">Footer</div>
</div>

jsFiddle


In Bootstrap 4.0, to have a fixed header and footer with scrolling content, wrap everything .container-fluid, as you likely are. Use .fixed-top and fixed-bottom class in your header and footer divs. Of course, you have to have enough content (overflow) so you can see it scrolling.


The flexbox approach by @Sticker worked nicely. For those on Bootstrap 4, you can avoid the custom CSS:

<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"/>

<html class="h-100">
  <body class="h-100">
    <div class="wrapper d-flex flex-column h-100">
      <div class="header">Header</div>
      <div class="content flex-grow-1 overflow-auto">
        <div style="height:1000px;">Content</div>
      </div>
      <div class="footer">Footer</div>
    </div>
  </body>
</html>