Footer at bottom of page or content, whichever is lower
Asked Answered
U

5

115

I have the following structure:

<body>
    <div id="main-wrapper">
        <header>
        </header>
        <nav>
        </nav>
        <article>
        </article>
        <footer>
        </footer>
    </div>
</body>

I dynamically load content in the <article> using javascript. Because of this, the height of the <article> block can change.

I want the <footer> block to be at the bottom of the page when there is a lot of content, or at the bottom of the browser window when only a few lines of content exist.

At the moment I can do one or the other... but not both.

So does anyone know how I can do this - get the <footer> to stick to the bottom of the page/content or the bottom of the screen, depending on which is lower.

Unblessed answered 2/9, 2012 at 19:42 Comment(0)
C
126

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.

Conciliatory answered 3/9, 2012 at 19:27 Comment(14)
I needed to add #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
Thank you, @Conciliatory for this thorough explanation, and especially for mentioning flex-direction (wish I'd found this sooner - would have saved me a couple of hours! :)Tranquil
The Flexbox version isn't working for me in IE11, but the other approach is fine for me! Thanks and +1!Quizzical
@Matt, you need to use browser prefixes to get flexbox to work in IE11. use a tool like autoprefixer and you'll never need to worry about adding them manually.Conciliatory
@zzzzBov: You mean, as described here?, e.g. -ms-flex-direction: column ?Quizzical
@Matt, MDN's documentation is consistently up-to-date, so I'll refer you there.Conciliatory
@zzzzBov: Thanks, so if I understand it correctly, it is rather like flex-direction: -ms-column, right?Quizzical
@Matt, I originally had the examples on CodePen. This was the flexbox example. Be sure to view the compiled CSS to see what browser prefixes actually get used. I mentioned autoprefixer before, because it's a tool I use to make my life easier. I literally don't remember what the exact browser-specific syntax is anymore because I just don't need to.Conciliatory
@zzzzBov: I noticed that footer and content are "flowing into each other." in that example, if I view it in IE11. In Chrome, it is displaying correctly.Quizzical
@Matt, good to know, I'll have to look into the issue when I have IE11 and time.Conciliatory
I dont understand why min-height: 100% doesnt work instead of height : 100%.Anitaanitra
@Matt, I've updated the flexbox version to include better cross-browser support, but IE11 has a known bug that's preventing this from working. Keep in mind, my post does say "If you're fortunate enough that you can use flexbox without needing to support older browsers..." at this point, Edge is the latest and IE11 is lumped into the "older browsers" category.Conciliatory
The sticky footer link appears to be broken due to his site being converted to an In Memoriam notice for him. In addition, there are no cached versions due to the settings of robots.txtTent
@Conciliatory I'm trying to do the sticky footer (flexbox version) but with scrollable content. I've got the question here if you want a stab at it: #48535806Marrs
K
13

Ryan Fait's sticky footer is a simple solution that I have used several times in the past.

Basic HTML:

<div class="wrapper">
    <div class="header">
        <h1>CSS Sticky Footer</h1>
    </div>
    <div class="content"></div>
    <div class="push"></div>
</div>
<div class="footer"></div>

CSS:

* {
    margin: 0;
}
html, body {
    height: 100%;
}
.wrapper {
    min-height: 100%;
    height: auto !important;
    height: 100%;
    margin: 0 auto -142px; /* the bottom margin is the negative value of the footer's height */
}
.footer, .push {
    height: 142px; /* .push must be the same height as .footer */
}

/*

Sticky Footer by Ryan Fait
http://ryanfait.com/

*/

Translating this to be similar to what you already have results with something along these lines:

HTML:

<body>
    <div class="wrapper">
        <header>
        </header>
        <nav>
        </nav>
        <article>
        </article>
        <div class="push"></div>
    </div>
    <footer>
    </footer>
</body>

CSS:

* {
    margin: 0;
}
html, body {
    height: 100%;
}
.wrapper {
    min-height: 100%;
    height: auto !important;
    height: 100%;
    margin: 0 auto -142px; /* the bottom margin is the negative value of the footer's height */
}
footer, .push {
    height: 142px; /* .push must be the same height as .footer */
}

Just dont forget to update the negative on the wrapper margin to match the height of your footer and push div. Good luck!

Kafiristan answered 2/9, 2012 at 19:45 Comment(6)
I love the way he put the comment at the bottom, appropriate for a footer solution :DBargainbasement
There's no need to change the markup for this particular style.Conciliatory
@Conciliatory I do not have much time to look into this further right now, but what exactly do you mean?Kafiristan
I'm on my mobile ATM so I can't write a full answer otherwise I'd have done that already. The comment was more so I'd remember to add an answer later.Conciliatory
@JoshMein, I've added an answer that explains how to make the footer stick without messing with the provided structure.Conciliatory
Loved it! and it worked like a charm! thank you sooo much man! you saved me.Verdellverderer
P
0

I was looking to solve this problem without adding any additional markup, so I ended up using the following solution:

article {
  min-height: calc(100vh - 150px); /* deduct the height or margins of any other elements within wrapping container*/
}

footer {
  height: 50px;
}

header {
   height: 50px;
}

nav {
  height: 50px;
}
<body>
  <div id="main-wrapper">
    <header>
    </header>
    <nav>
    </nav>
    <article>
    </article>
    <footer>
    </footer>
  </div>
</body>

You have to know the heights of header, nav and footer to be able to set the min-height for the article. By this, if article has only few lines of content, the footer will stick to the bottom of the browser window, otherwise it will go below all the content.

You can find this and other solutions posted above here: https://css-tricks.com/couple-takes-sticky-footer/

Providence answered 2/4, 2019 at 12:28 Comment(0)
P
0

I will like to approach this with css-grid. I will make two-part in your #main-wrapper div. The first one is for content and the second one is for footer.

// HTML 

<body>
<div id="main-wrapper">
  <div class="main-content">
    <header></header>
    <nav></nav>
    <article></article>
  </div>
  <footer class="footer">
    footer
  </footer>
</div>
</body>

In css

#main-wrapper {
  min-height: 100%;
  display: grid;
  grid-template-rows: 1fr auto;
}
.footer {
  grid-row-start: 2;
  grid-row-end: 3;
  background-color: #a45657;
  color: white;
  text-align: center;
  padding: 10px;
  font-size: 20px;
}

You can check the working demo here (Please check-in project view). This code is taken from my favorite CSS site css-tricks.

Penetrate answered 17/3, 2021 at 5:37 Comment(0)
T
0

2023 - Here's the css only solution. Make 90vh whatever works for your footer.

<div style= "min-height:90vh">
    ... your content
</div>
<div>
   ... your footer
</div>
Toein answered 20/12, 2022 at 0:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.