Responsive, Flexible-Height Sticky Footers in CSS

Since I’ve been in the game, front-end devs have been wrestling with sticky footers like it was going out of style. I’m no exception, but today I learned a trick that made things a lot easier.

Before we go on though, I’d like to explain the problem briefly. It’s common for websites to have a header, a content section and a footer. On pages with a lot of content, the content takes up enough vertical space to push the footer to the bottom of the browser window. But, on pages with little content, sometimes the content does not take up enough vertical space to push the footer to the bottom of the window. This leaves the footer sitting oddly in the middle of the screen.

There are several solutions, each with their own pros and cons.

The Old Way

The old way works well, except that it relies on the footer to be a fixed height at all times. In responsive sites, this is rarely the case. Of course, you could write JavaScript that detects the footer height and adjusts the CSS accordingly, but that’s neither clean nor performant. A CSS-only solution would be better.

The display: table Trick

My new favorite approach to the problem looks something like this:

The only real caveat to this solution that I’ve encountered so far is the styling limitations present with elements using display: table-row. Often padding, margin, etc. don’t behave as expected. This is easy enough to work around by adding a <div> or something inside the .page-row and styling that:

Why not Flexbox?

As I understand it, Flexbox handles sticky footers very well. If you’re in a position to be able to use Flexbox without worrying about browser support, go for it!

17 Comments

  • Jake Lazaroff says:

    Question: if you’re going to use all this markup, and use table display values… why not just use a table? In this case the header would be a and header-inner would be a (or a ). See Eric Meyer’s take: http://meyerweb.com/eric/thoughts/2004/09/05/css-grids/

    • Galen Gidman says:

      Meyer’s post is almost 10 years old. Thankfully, we’ve come a long way since then and I doubt he’d still feel the same, at least in that scenario.

      Even in this case, I don’t see why you would want to use a table. You’d still have to write some CSS — albeit a bit less of it — for the solution to work, but you’d have to write way more markup: http://galen.in/9LKt

  • Scott says:

    This is actually a pretty cool solution to the responsive footer issue. Thank you for sharing.

    And per the first reply here, using a table would not be a good choice for so many reasons, semantic mark-up being at the top of the list.

  • Adam B says:

    So, what’s the problem with using absolute or fixed positioning for your layout? Or do you want the content of the body to push the footer down if the content is longer than the page? In that case, I think I’d just roll a SASS- or LESS-based solution (if that’s an option) to set the min-height of the body to the available space on the page. I avoid table layouts like the plague, if I can (though they have their place).

    • Galen Gidman says:

      Yes, the idea is for the body to push the footer down if it is longer than the page. As far as using a Sass- or LESS-based solution, that’d still require some JavaScript, which is what this solution seeks to avoid.

    • Adam B says:

      I was referring to just specifying the min-height using a percentage minus the header and footer heights using SASS / LESS. Are you saying they’re using client-side JavaScript on the back-end to accomplish this?

      Note: I’m still pretty new to these techs, so I really don’t know what’s going on in the background :)

    • Galen Gidman says:

      As far as I know, the only way this would work is if the header and footer were sized with percentages as well. Generally this is not the case, but I imagine it could work in a few scenarios.

    • Adam B says:

      SASS/LESS actually let you do math operations with mixed types (ex: setting min-height to 100% – 120px)

    • Galen Gidman says:

      I’m pretty sure that isn’t actually the case. As I understand, it might work in CSS calc(), but not in LESS/Sass.

  • Thanks! I tried this and have been using this on my blog for a while now. One caveat I ran into is that because the behaviour of table cells is that they won’t collapse smaller than the minimum size of their content, it’s a bit tricky to get overflow: scroll to work on elements containing non-wrapping text. Like code blocks on a blog. I haven’t really settled on a solution yet, but thought I’d give a heads up on the issue.

    • Well, of course right after writing that I did figure a passable solution. For my case it’s enough to give pre elements inside articles max-width: 90vw;, but that’s not really a general solution, nor does it have perfect browser support.

  • Thank you for this solution. I’ve been trying loads of different approaches, but none suited my needs. A thing to mention tho is, if you wrap your whole site in a div to center your site on a maximum width, it doesn’t work anymore. Really, don’t know why not. My solution to this was quite simple: I took the wrapping div out of my html and added the CSS to center my website to my body-tag. I don’t know how cross-browser this is, but it works fine on Chrome, Safari and my Android (chrome). For example:

    body {
    	display: table;
    	max-width: 990px;
    	margin: 0 auto;
    }

    This also means that its kind of responsive. Every window that’s smaller than 990px just narrows the site. I have this straight-forward 1 column site with a header on top, a main in the middle and a footer at the bottom. When using a background-image and background-size: contain to handle my graphics in header and footer, the size of these graphics also scale down depending on the width of the window. Simple, and it works.

    Thank you,
    Marijn
    Belgium

  • Matt says:

    Thanks very much for sharing this. I was having trouble with images set to max-width: 100% not scaling down. Just incase anyone is having the same problem the fix which I found on Stack Overflow was to put table-layout: fixed on the element that is set to display: table.

    http://stackoverflow.com/questions/2923710/why-do-firefox-and-opera-ignore-max-width-inside-of-display-table-cell

  • Patrick says:

    I’m having a doozy trying to debug why the vertical scroll bar created with the content pushing down the footer using this method, also creates a horizontal scroll bar in the browser. When the content is in the view port, the horizontal scrollbar doesn’t exist. No matter what browser I use, this happens.

    http://superiorsample.com/newsite/index.cfm

  • Dreamvention says:

    Great solution. thanks!

    For some reason, it didn’t quite work – the height of 100% would through my footer below the screen size so I had to change it a bit. hope this helps.

    html,
    body {
      height: 100%; 
    }
     
    body {
      display: table;
      width: 100%;
    }
     
    body > * {
      display: table-row;
      height: 1px;
      box-sizing: border-box
    }
     
    main { 
      height: 100%; 
    }
  • Timo says:

    Bookmarked, and used! This is the perfect solutions. I’ve been looking for this for ages, everyone should know this!

  • Just the solution I was looking for, thanks for sharing and saving me some time (and headache :))

  • Leave a Reply

    Your email address will not be published. Required fields are marked *

    You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>