Ryan Fait's sticky footer is very nice, however I find its basic structure to be lacking*.
Flexbox Version
If you're fortunate enough that you can use flexbox without needing to support older browsers, sticky footers become trivially easy, and support a dynamically sized footer.
The trick to getting footers to stick to the bottom with flexbox is to have other elements in the same container flex vertically. All it takes is a full-height wrapper element with display: flex
and at least one sibling with a flex
value greater than 0
:
CSS:
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#main-wrapper {
display: flex;
flex-direction: column;
min-height: 100%;
}
article {
flex: 1;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#main-wrapper {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
min-height: 100%;
}
article {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
}
header {
background-color: #F00;
}
nav {
background-color: #FF0;
}
article {
background-color: #0F0;
}
footer {
background-color: #00F;
}
<div id="main-wrapper">
<header>
here be header
</header>
<nav>
</nav>
<article>
here be content
</article>
<footer>
here be footer
</footer>
</div>
If you can't use flexbox, my base structure of choice is:
<div class="page">
<div class="page__inner">
<header class="header">
<div class="header__inner">
</div>
</header>
<nav class="nav">
<div class="nav__inner">
</div>
</nav>
<main class="wrapper">
<div class="wrapper__inner">
<div class="content">
<div class="content__inner">
</div>
</div>
<div class="sidebar">
<div class="sidebar__inner">
</div>
</div>
</div>
</main>
<footer class="footer">
<div class="footer__inner">
</div>
</footer>
</div>
</div>
Which isn't all that far off from:
<div id="main-wrapper">
<header>
</header>
<nav>
</nav>
<article>
</article>
<footer>
</footer>
</div>
The trick to getting the footer to stick is to have the footer anchored to the bottom padding of its containing element. This requires that the height of the footer is static, but I've found that footers are typically of static height.
HTML:
<div id="main-wrapper">
...
<footer>
</footer>
</div>
CSS:
#main-wrapper {
padding: 0 0 100px;
position: relative;
}
footer {
bottom: 0;
height: 100px;
left: 0;
position: absolute;
width: 100%;
}
#main-wrapper {
padding: 0 0 100px;
position: relative;
}
footer {
bottom: 0;
height: 100px;
left: 0;
position: absolute;
width: 100%;
}
header {
background-color: #F00;
}
nav {
background-color: #FF0;
}
article {
background-color: #0F0;
}
footer {
background-color: #00F;
}
<div id="main-wrapper">
<header>
here be header
</header>
<nav>
</nav>
<article>
here be content
</article>
<footer>
here be footer
</footer>
</div>
With the footer anchored to #main-wrapper
, you now need #main-wrapper
to be at least the height of the page, unless its children are longer. This is done by making #main-wrapper
have a min-height
of 100%
. You also have to remember that its parents, html
and body
need to be as tall as the page as well.
CSS:
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#main-wrapper {
min-height: 100%;
padding: 0 0 100px;
position: relative;
}
footer {
bottom: 0;
height: 100px;
left: 0;
position: absolute;
width: 100%;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#main-wrapper {
min-height: 100%;
padding: 0 0 100px;
position: relative;
}
footer {
bottom: 0;
height: 100px;
left: 0;
position: absolute;
width: 100%;
}
header {
background-color: #F00;
}
nav {
background-color: #FF0;
}
article {
background-color: #0F0;
}
footer {
background-color: #00F;
}
<div id="main-wrapper">
<header>
here be header
</header>
<nav>
</nav>
<article>
here be content
</article>
<footer>
here be footer
</footer>
</div>
Of course, you should be questioning my judgement, as this code is forcing the footer fall off the bottom of the page, even when there's no content. The last trick is to change the box model used by the #main-wrapper
so that the min-height
of 100%
includes the 100px
padding.
CSS:
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#main-wrapper {
box-sizing: border-box;
min-height: 100%;
padding: 0 0 100px;
position: relative;
}
footer {
bottom: 0;
height: 100px;
left: 0;
position: absolute;
width: 100%;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#main-wrapper {
box-sizing: border-box;
min-height: 100%;
padding: 0 0 100px;
position: relative;
}
footer {
bottom: 0;
height: 100px;
left: 0;
position: absolute;
width: 100%;
}
header {
background-color: #F00;
}
nav {
background-color: #FF0;
}
article {
background-color: #0F0;
}
footer {
background-color: #00F;
}
<div id="main-wrapper">
<header>
here be header
</header>
<nav>
</nav>
<article>
here be content
</article>
<footer>
here be footer
</footer>
</div>
And there you have it, a sticky footer with your original HTML structure. Just make sure that the footer
's height
is equal to #main-wrapper
's padding-bottom
, and you should be set.
* The reason I find fault with Fait's structure is because it sets the .footer
and .header
elements on different hierarchical levels while adding an unnecessary .push
element.
#main-wrapper *:first-child { margin-top: 0; }
, otherwise the page would be too long by the first child's top margin (causing an unnecessary scrollbar on short pages). – Earmuff