A brief history, if you will.
The purpose of a sticky footer is that it "sticks" to the bottom of the browser window. But not always, if there is enough content on the page to push the footer lower, it still does that. But if the content on the page is short, a sticky footer will still hang to the bottom of the browser window.
There is negative bottom margins on wrappers
There was a wrapping element that held everything except the footer. It had a negative margin equal to the height of the footer. That was the basis of this one.
<body>
<div class="wrapper">
content
<div class="push"></div>
</div>
<footer class="footer"></footer>
</body>
html, body {
height: 100%;
margin: 0;
}
.wrapper {
min-height: 100%;
/* Equal to height of footer */
/* But also accounting for potential margin-bottom of last child */
margin-bottom: -50px;
}
.footer,
.push {
height: 50px;
}
See the Pen Sticky Footer with calc(); by Chris Coyier (@chriscoyier) on CodePen.
This one required an extra element inside the content area (the ".push
"), to ensure that the negative margin didn't pull the footer up and cover any content. The push was also clever because it very likely didn't have any bottom margin of it's own. If it did, that would have to be factored into the negative margins, and having those two numbers not in sync doesn't look quite as nice.
There is negative top margins on footers
This technique did not require a push element, but instead, required an extra wrapping element around the content in which to apply matching bottom padding to. Again to prevent negative margin from lifting the footer above any content.
<body>
<div class="content">
<div class="content-inside">
content
</div>
</div>
<footer class="footer"></footer>
</body>
html, body {
height: 100%;
margin: 0;
}
.content {
min-height: 100%;
}
.content-inside {
padding: 20px;
padding-bottom: 50px;
}
.footer {
height: 50px;
margin-top: -50px;
}
See the Pen Sticky Footer with Negative Margins 2 by Chris Coyier (@chriscoyier) on CodePen.
Kind of a wash between this technique and the previous one, as they both require extra otherwise unnecessary HTML elements.
There is calc() reduced height wrappers
One way to not need any extra elements is to adjust the wrappers height with calc(). Then there is not any overlapping going on, just two elements stacked on top of each other totaling 100% height.
<body>
<div class="content">
content
</div>
<footer class="footer"></footer>
</body>
.content {
min-height: calc(100vh - 70px);
}
.footer {
height: 50px;
}
See the Pen Sticky Footer with calc(); by Chris Coyier (@chriscoyier) on CodePen.
Notice the 70px in the calc() vs. the 50px fixed height of the footer. That's making an assumption. An assumption that the last item in the content has a bottom margin of 20px. It's that bottom margin plus the height of the footer that need to be added together to subtract from the viewport height. And yeah, we're using viewport units here as another little trick to avoid having to set 100% body height before you can set 100% wrapper height.
There is flexbox
The big problem with the above three techniques is that they require fixed height footers. Fixed heights are generally a bummer in web design. Content can change. Things are flexible. Fixed heights are usually red flag territory. Using flexbox for a sticky footer not only doesn't require any extra elements, but allows for a variable height footer.
<body>
<div class="content">
content
</div>
<footer class="footer"></footer>
</body>
html {
height: 100%;
}
body {
min-height: 100%;
display: flex;
flex-direction: column;
}
.content {
flex: 1;
}
See the Pen Sticky Footer with Flexbox by Chris Coyier (@chriscoyier) on CodePen.
You could even add a header above that or more stuff below. The trick with flexbox is either:
flex: 1
on the child you want to grow to fill the space (the content, in our case).- or,
margin-top: auto
to push the child away as far as it will go from the neighbor (or whichever direction margin is needed).
Remember we have a complete guide for all this flexbox stuff.
There is grid
Grid layout is even newer (and less widely supported) than flexbox. We have a complete guide for it too. You can also fairly easily use it for a sticky footer.
<body>
<div class="content">
content
</div>
<footer class="footer"></footer>
</body>
html {
height: 100%;
}
body {
min-height: 100%;
display: grid;
grid-template-rows: 1fr auto;
}
.footer {
grid-row-start: 2;
grid-row-end: 3;
}
This demo should work in Chrome Canary or Firefox Developer Edition, and can probably be backported to the older version of grid layout for Edge:
See the Pen Sticky Footer with Grid by Chris Coyier (@chriscoyier) on CodePen.
This always worked for me. The position relative on body is required to make it work.
html { height: 100%; }
body {
min-height:100%;
position:relative;
padding-bottom:[footer-height]
}
.footer {
position: absolute;
left: 0 ; right: 0; bottom: 0;
height:[footer-height]
}
For the Flexbox example, you can also use vh units which is ever-so-slightly less code:
This, naturally, depends on your level of browser support. But it’s another option! (Note that if for whatever reason you have a content wrapper you can’t get rid of—something I just ran into while working in an Ember app—the
body
code should be on that wrapper.)Long before Flexbox, there was also a way to make sticky footer with
display:table
anddisplay: table-footer-group
: http://codepen.io/SelenIT/pen/QELpww. It has some drawbacks (e.g. needs extra wrappers just to add paddings), but it is supported back to IE8. Should it be also mentioned here?Wow… I’ve never thought of this one. Seems pretty bullet-proof. Sucks that you have to have the wrappers, but I like it!
I think we can do it without extra element (without “push” nor “content-inside”): http://codepen.io/thierry/pen/zBOZvz
Sticky footer via display table-cell is missing: https://gist.github.com/goldsky/7322156
i prefer the flexbox approach, but just wanted to throw one more option into the mix…
sticky footer with
display: table-row
http://codepen.io/puglyfe/pen/QELpGy
I’ve been using a jQuery function to add a ‘fixed’ class to the footer if the content-height is less than the page-height. Just drop it into the JS functions and no extra work.
As much as I like a css-only solution, it depends on either extra markup or the page content being (window-height – footer-height) and sometimes the content-height is much shorter.
That solution is a nightmare, when content changes dynamically.
Don’t forget position sticky! It would be a pretty terrible thing to use in the wild for this purpose, but it does (kinda) work – something to add to the list.
(Demo will only work in Firefox or Safari)
I like the flex box approach. Just an FYI. On a recent project I tried to set the height of the container to calc (100vh – 50px) and while it works for android and all desktop browsers, it doesn’t work on iOS devices. The vh inside the calc specifically. Very annoying. So thanks for showing the flex: 1; so helpful.
Be careful using the flex shorthand, different browsers (working to different specs at time of shipment) have different default values https://github.com/philipwalton/flexbugs#6-the-default-flex-value-has-changed – It may be safer to avoid shorthand for now (or build a mixin that does it for you)
This is also a great resource for some crossbrowser flexbox issues, most of which have fairly trivial workarounds
https://github.com/philipwalton/flexbugs