Sticky CSS footers: The flexible way

Update: I’ve developed the idea of this article a bit further to a simple CSS based layout grid, which also includes flexible columns and some other improvements. However, this article is still worth reading to get a basic idea of how the flexible footer works.

A CSS sticky footer is an area, that stays at the window bottom if there is not enough content to fill the complete window height, but stays below the content if its height exceeds the window height. There are several ways how to achieve this circulating in the web, but they all have some flaws: Most of them (e.g. CSSStickyFooter) require a fixed height footer and the only flexible solution I’ve found needs jQuery. However, here is an easy and plain CSS solution for sticky footers with fluid height that works perfectly with IE8+, FF2+, Chrome9+, Safari3+ and Opera 8+ (probably more) and returns acceptable results in IE7 and IE6.

For those of you, who don’t care about big explanations, I’ve made a simple example page and a bit more complex one to show you how it will look like. You can check out the code (it’s quite simple) in your browser or download everything as an ZIP archive or read on, if you want to know all the details.

Three steps to happiness

The basic thought behind the idea is simply to use a CSS table instead of block elements – Wait! Isn’t the use of tables for layout purposes from the dark side of web design!? Well, sort of. If we would use the HTML table tag here, I would totally agree, but we’re using the CSS display: property here, which is purely visual with no semantic purpose at all, so I can’t see any problem here. But enough talk, here is how we do it.

First of all we need the HTML that we’re going to style:

<body>
    <header><h1>Catchy header</h1></header>
    <section><h2>Awesome content</h2></section>
    <footer><h3>Sticky footer</h3></footer>
</body>

Pretty straightforward – no mystical div tags or strange nestings – just plain HTML5.

Step 1: By default the body of a HTML page has not the height of the browser window, but expands with the content of the page. So how do we make it match the window size? Setting the height of the page body to 100% won’t do the job. The problem is, that the height of the whole page itself – yeah right, we’re talking about the html tag here – has to be set, too. So the first CSS style looks like this:

html, body {
    height: 100%;
    margin: 0pt;
}

The margin is set to zero just to make sure there are no spaces that mess up the layout.

Step 2: Now comes the CSS table stuff. What we need is a frame which contains the table rows, the row elements itself and a possibility to expand a row to the maximum possible height. Setting the height of an display:table element (the frame) to 100% will cause it to expand over the whole available height, but it will still grow beyond it, if its content needs more space. So it works more like the min-height: attribute, but that’s exactly what we need here. width:100% ensures that the frame always spans the the full available width. The table rows are simply display:table-row elements. height:1px will ensure that the normal rows will use as few space a possible, while the remaining space will be distributed among the expanded rows with height:auto/code>.

.Frame {
    display: table;
    height: 100%;
    width: 100%;
}
.Row {
    display: table-row;
    height: 1px;
}
.Row.Expand {
    height: auto;
}

That’s basically all the CSS we need to get a sticky and flexible footer in modern browsers.

Step 3: All we have to do now is to put our CSS and HTML code together. Fortunately we can use the body element as .Frame, so there is no need for an extra div tag or so.

<!DOCTYPE HTML>
<html>
<head>
    <style type="text/css">
        html, body {
             height: 100%;
             margin: 0pt;
        }
        .Frame {
             display: table;
             height: 100%;
             width: 100%;
        }
        .Row {
             display: table-row;
             height: 1px;
        }
        .Row.Expand {
             height: auto;
        }
    </style>
</head>
<body class="Frame">
    <header class="Row"><h1>Catchy header</h1></header>
    <section class="Row Expand"><h2>Awesome content</h2></section>
    <footer class="Row"><h3>Sticky footer</h3></footer>
</body>
</html>

Note: Remember to include the html5shiv workaround in your page (and define appropriate CSS styles) if you want to use HTML5 tags in IE8 and below. Or simply use div tags instead of header, section and footer.

A word on older browsers

The code above will work even with older versions of Firefox, Opera and Safari, so there is nothing to worry about here, but unfortunately Internet Explorer 7 and below don’t know anything about display:table or display:table-row, so we go the way of graceful degradation here.

The first thing we have to to is, to prevent the margins of elements inside the row from being outside of it, by adding overflow:hidden to the .Row style.

That gives us quite acceptable results, but you will always have scrollbars due to the 100% height of the .Frame. The solution is to set height:100% in a way that all Internet Explorer versions below 8 won’t recognize. I’m using the (valid) html>/**/body CSS hack to accomplish this, but you might also use conditional comments if you feel better that way. However, here is the fixed CSS:

.Frame {
    display: table;
    width: 100%;
}
html>/**/body .Frame {
    height: 100%;
}
.Row {
    display: table-row;
    height: 1px;
    overflow: hidden;
}
html>body .Row.Expand {
    height: auto;
}

I guess it shouldn’t be too complicated to create a sticky footer by adjusting the height of .Row.Expand with some little Javascript.

Some final words

That’s it, you now have a flexible sticky footer made of valid HTML/CSS, which renders correctly in all common browsers and returns acceptable results in older browsers. Static heights will work as well (just the height attribute for a specific row and I think it’s quite simple to add columns to the layout by setting display:table-cell for the child elements of the rows. Finally once again the links to the simple and complex examples and the ZIP archive.

Errata

Opera height issues: Opera uses the full height of the .Frame element to convert height values from percent to pixels. This causes each expanded row, which contains a child element with height:100% or similar, to be as high as the whole frame. Fix: Use height:1px for normal rows and and height:auto for expanded rows. (all examples fixed on 2012-03-06)

48 thoughts on “Sticky CSS footers: The flexible way

  1. Nice writeup, was wondering if there was a variable height sticky footer and came across this. There’s something about using table properties that grates, but I’m all for a pragmatic approach :)

    Unfortunately on my first attempt this seems flawed, with some of the .row elements also expanding in height with increased page height. Might not matter with some designs, does with the one I’m working on.

    Thanks.

    • Thx :) I’m not 100% sure what exactly your problem is. Can you give me an URL a page that shows the issue? I’d like to try to fix it…

      • I could sort it myself I’ve no doubt, but already reverted the changes. Sorry. It’s possible the problem only occurs when you resize the window, so redrawing rather than on the initial page load.

  2. Hello torben,
    Thanks for sharing this.
    This method allows me to pull down background color until the footer.
    Other sticky footers don’t do this.

    But I got a problem with opera.
    I’m trying to make this http://www.mediafire.com/i/?a5zmt3k58b1cd4e .
    The HTML and additional CSS is in here https://gist.github.com/1744347

    Other browsers (FF, Safari, Chrome) works fine, but not Opera, because it pushes again another margin-bottom.

    Do you have any idea how to fix this?

    Thanks ahead.
    Rico.

    • Adding display:table-cell and removing height:100% from the #content-wrapper styles could solve your problem.

      However, Opera has still some issues when sizing an element with relative values (e.g. height:100%) within a table (<table> as well as display:table). It seems that Opera always uses the dimensions of the whole table and not of the table-row or -cell.

      PS: I’ve sent a bug report to Opera Software and I’m already testing a workaround that tackles this issue, so if everything works out you could expect an update of the sticky footer code next week…

  3. Pingback: This CSS layout grid is no Holy Grail | Pixels vs. Bytes

  4. I am certainly hoping this works as well as it reads and demos. It will be great to have a nice valid css footer that does what I actually want and stays in the right position.

  5. Thanks for sharing your code, I love how it works. But it seems that in ie8 & 9 text can’t be selected at all (or doesn’t show what is being selected.) It’s a bit of a tragic error.

    I don’t know why the error exists but I think I’ve narrowed this down to the “Frame” and found (from what i can tell) that it’s not necessary. See the build here: http://jsfiddle.net/KJusE/

      • Yeah, there are some issues with putting content directly into a table-row. Dunno, why the browsers are so picky in that particular point, but fortunately most of the problems can be solved by putting the content into a table-cell. Thanks for pointing it out, anyway :)

  6. It seems that this no longer works in Webkit. The content does not expand to fill the height of the viewport and there’s an equal amount of space above the header and below the footer.

    • …I stand corrected, it does work with one minor modification. The expanding element’s height needs to be set to 100% instead of auto. This appears to work under Gecko as well.

      • I’ve just tested my examples with Chrome and Safari and didn’t see any problems. In what browsers the problems occur exactly? On the the other hand you might have been running into a problem I described and solved in my “Holy Grail” layout grid article (it’s linked in the first paragraph).

        BTW: Setting the expanding height to 100% might cause problems with other browsers. AFAIR Opera doesn’t like it, but this might have changed during the last year…

    • Yap, that’s right, but IMHO web developers should look forward instead of looking back and I think you shouldn’t care too much about a 6 year old browser with 3% percent market share (see Wikipedia).

      • Sometimes it’s not only the market share of int_er_netsites.

        Many Companies still have IE7 or IE6 in their int_ra_nets. As a developer for such companies you have to deal with this.

        • You’re right, but IMHO these are special cases. I personally try to build websites, which are usable with all browsers, but when it comes to the look’n’feel (and I guess a sticky footer fells into this category) I go the way of graceful degradation.

  7. Hi, i have a problem with chrome and jquery, though it works ok in IE and FF.

    When i add to my page (no matter where i put it), chrome automatically adds a big margin after the footer. I`ve checked with Chrome`s “Firebug” and nothing new appears. But if i uncheck and recheck the display:table property from Frame class, the extra margin disappears.

    Any ideas?
    Thanks in advance.

    • Hmm, that’s strange indeed. I’m using the “Holy Grail” grid, which is kind of the big brother of this sticky footer here, on a page wich makes extensive use of JQuery and never experienced any problems.

      I’m pretty sure it’s some kind of correlation between your code, the footer and JQuery, so it would be good to reduce the page code as much as possible to isolate the problem. For example: Does the bug also appear when you include JQuery in one of my example pages? If not, what do you have to add from your code until the bug occurs?

      It could also be a problem with a browser extension – at least one (Window Resizer in Chrome) is known to cause problems. See the Errata at the end of the Holy Grail post for an explanation and a workaround…

      • Stripped down to just the code outlined in the example above (excluding holy grail, jquery, etc… ) the current version of webkit browsers will not let the table take the full height of the document.

        The way around this – as noted by Fraxtail above is to change the .Row.Expand class to height: 100%; — simple fix, and it still works in FF, etc.

        • Well this is strange, because I just can’t recreate the bug, where WebKit browsers won’t let the table take the full height (my examples work fine for me with Chrome & Safari on Win, Mac and Linux). Can you give me a link to an example page, where that problem occurs? Since more than one person has this problem I’d really like to investigate it further…

          • Sorry, but i don`t have it anymore. Thanks to your “Holy Grail”. I merged it with the content and styles that i needed, and works great now.

            Thanks a lot for your code and replies.

          • Hi. I have the same issue as above (I guess). Here is my code: http://pastebin.com/D593phCD

            Just a simple example code from this page with added jQuery and the height is messed up (footer does not stick to the bottom) in current Mac Chrome as well as in Safari. Chrome under Win7 does not work for me either. Only FF does.

            I would be really interested in finding solution. It’s pretty strange bug for me.

  8. Hi Torben,
    Frist of all, I would like to thank you your clear, simple and understandable contributions about web development. All of them show a high level of creativity and smart solutions.
    I have been trying to recreate “Sticky CSS Footers” with equalized columns inside the main container and it seems that Mozilla and Webkit browsers (mac and PC) respond quite good. Since IE and Opera don’t show properly the 100% height inside a container with auto height, I included JQuery to equalize the columns. The result was an error in the Webkit browsers and the sticky CSS footers don’t work out. Firefox, Opera and IE with loaded JQuery show properly your layout. You can see the behavior in this link http://html-test.freeserver.me/html-test/. The question is: Is there some way to create a layout like this without using Javascript and cross-browser?
    Thanks in advanced.

  9. Hi Torben,
    Thanks a lot for your answer. I followed your tutorial through the link you posted. The solution is brilliant! Nevertheless it is not to working out in Opera version 12.14 for mac. The grid is not equalized. The screenshot in this link http://html-test.freeserver.me/opera-js-event-fail.png shows the behavior. It seems that Opera doesn’t understand the events “onload” “onresize” inside the conditional statement. If the events are placed outside the conditional, Opera renders the grid perfectly. I will follow your blog to see if someone finds the squaring of the circle.

  10. Pingback: How to center horizontal table-cell - How-To Video

  11. Tried your sôlution, it works fine :-)
    but – table-row prevents the use of margin and padding – so not usable for what I have to do right now.

    • Hej :) Yes, you’re right table-row elements don’t support margin and padding (as well as borders), but you can easily fix that by putting a table-cell element inside the table-row element.

  12. Hey there, great article, saved my day. Just one problem. Current versions of Chrome, Opera and Safari for Windows leave a huge white space after the footer, almost like it didn’t stick. Check this website for an example: http://www.arteria.com.br/site/

    I’ve tried height:100% in the .Expand, but it didn’t work. Works fine on IE 9+ and FF.

    • Hej Jean,

      The code is working for me with all browsers (including Chrome, Opera and Safari). I tested the example pages, so the problem on your page might be a side effect of some other code you’re using. BTW: I wasn’t able to find neither any of my code on your page nor just one display:table element the linked website. Have you removed the code again?

      Bai
      Torben

  13. I’m used to wrapping tables (div) in my RWDs (if the table is too wide, use overflow:auto to scroll horizontally) but for some reason using “table-row” makes that completely useless; the table will ignore the parent’s overflow and width causing the much unwanted viewport horizontal scrollbar.
    I haven’t found a way around this, so until I do, I will not be able to use this fantastic sticky footer.

  14. Can’t believe I didn’t find this until now! Amazing. One suggestion:

    .Frame should have table-layout: fixed;

    I discovered that if I have an element using my truncate class (see below), it would cause the width of .Frame to exceed the window width if the text overflowed.

    Thanks for this friend!

    For reference:
    .truncate { overflow: hidden; padding-bottom: 0.2em; width: 100%; text-overflow: ellipsis; white-space: nowrap; }

  15. I just want to say a massive thank you! I searched everywhere for a solution like this! I thought I was going to have no hair left!

    But this is EXACTLY what I needed! All the other solutions meant you had to have fixed div heights, not something I could use as this is going on a wordpress site!

    Thank you again!

  16. Pingback: Sticky CSS footers: The flexible way | Eduardo Akio Fukunari - Blog

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>