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!

41 thoughts on “Responsive, Flexible-Height Sticky Footers in CSS

    1. 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:

  1. 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.

  2. 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).

    1. 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.

    2. 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 :)

    3. 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.

  3. 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.

    1. 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.

  4. 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,

  5. 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.

  6. 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.

    body {
      height: 100%; 
    body {
      display: table;
      width: 100%;
    body > * {
      display: table-row;
      height: 1px;
      box-sizing: border-box
    main { 
      height: 100%; 
    1. body > * {
      display: table-row;

      …causes entire contents of Javascript children (i.e. the code itself) to be displayed onscreen, with IE, Firefox and Chrome. It may be a bug with all browsers, but can be mitigated with

      body > :not(script) {
      display: table-row;

      1. Or maybe better, for <=IE8 compatibility, after the body > * {...}

        body > script { display: none; }

        There’s an inherent warning about use of * selector with CSS display style. The script nodes are still part of the DOM, though will default to display: none through browser default styles, but if your CSS overrides that, your scripts will be displayed.

        Also worth noting that the solution here requires margin: 0 on the body element to work correctly.

  7. Any reason why you haven’t cited your sources on this? This article/technique was written very similarly to one or two others that predate your post. Could you clarify?

    1. I don’t remember where I learned this technique originally. As far as my article being similar to others on the subject, that shouldn’t be surprising given that any article on a topic as specific as this is going to follow a similar flow and have nearly identical code examples. If you were to Google other common questions, I’m sure you’d see the same thing.

  8. I was stuck on this and all other solutions I found didn’t work for me but this one works great, for which I am thankful!

  9. I have designed a responsive web page with less content in it. And in some responsive layouts the footer is not stuck to the bottom of browser window.

    I have tried all the solutions mentioned above in this blog, but none of them is working for me.

    Can anybody help me in this problem?
    I have simple body structure like this:

    And CSS like this:
    header{ width:100%; float:left; padding:0; margin:0;}

    section{ width:100%; float:left; margin:0px; padding:0px}

    footer{width:100%; float:left; padding:25px 0 25px 0; margin:20px 0 0 0;border-top:1px solid #dbe2e5;}

    Please reply me as soon as possible.
    Thanks in advance

    1. WordPress ate the markup you posted, but I can see right away that you’re floating your major page elements, which is not recommended. I imagine you’re doing that as a method of clearing floated child elements, but there are better ways to do that. Try one of those and see if that helps.

  10. Thanks for sharing this Galen. Nice solution! Is there a way to get the content area to throw scrollbars? If I set overflow it just gets ignored and continues to push the page height.

  11. Hi,

    I’m having issues with my sticky footer not being scrollable when I collapse the browser window. I need it fixed all the time not just at the bottom of the main content area, so hope someone can help out as I’m searching the web without luck, and am a newbie with code. Please could someone kindly reply to my stack overflow post here…(below), there’s two issues I need help to address.


  12. Hello Galen,

    I’ve had a problem with your solution in WordPress when logged in. The WP-admin bar is position: fixed and screws it up! I’ve tried to replicate the problem in a JSFiddle:

    If you could have a look as I wish to keep the wp admin bar fixed.



      1. Cheers, This sorted it but adds in the height of the admin bar at the bottom so the window scrolls. Is there a way of fixing this?

        Nb: It’s not too important for WP as only the moderator would see the bar.

      2. I sorted it:

        html { margin-top: 0px !important; }
        * html body { margin-top: 0px !important; }
        body.admin-bar header nav {margin-top: 32px;}
        @media screen and ( max-width: 782px ) {
        html { margin-top: 0px !important; }
        * html body { margin-top: 0px !important; }
        body.admin-bar header nav {margin-top: 46px;}

  13. This works beautifully. I’m having trouble, however, making this work with any of the jQuery plugins for slideout navigation menus that I’ve tried. Have you tried using this trick with off-canvas navigation menus? Any particular one that worked?


  14. Wonderful!

    The only oddity I’ve seen is that on my Android phone, in both Firefox and Chrome but not in the stock Android browser, the page-row-expanded element is HUGELY long. Perhaps something like 800 or 900% the size of the content. For the moment, I’ve just used media queries to force phones and tablets to ignore the stick-footer selectors which is, honestly, probably for the best since they’re likely unnecessary at those screen sizes. However, if anyone’s got any thoughts as to what’s going on, I’d love to hear ’em.

  15. Nice solution.

    On pages where content is too small, I notice the footer jumps from the middle of the page (where the content ends) to the footer area.

    Is there a way to avoid this jump?

Share Your Thought