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.

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

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

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

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

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

    2. You might want to check the article I’ve posted today, which describes how to create a flexible CSS layout grid (including sticky footer). I’ve tried to fix most of the height issues of the code in this article. Hope it works for you…

      Here’s the link: http://pixelsvsbytes.com/blog/2012/02/this-css-layout-grid-is-no-holy-grail/

  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.

    1. AFAIK it works :) Since you and a lot of other people still seem to use the code of this article here, I’ve backported a fix for a minor Opera bug from my CSS layout grid post (http://pixelsvsbytes.com/blog/2012/02/this-css-layout-grid-is-no-holy-grail/), so you might want to update your code as well. Look at the errata section for details…

  5. I’ve got this working absolutely great in Chrome, but on Firefox if the expanded row has a lot of data then even with `overflow: auto` added it pushes the footer off the page. Have you come across this? I’ve posted up the problem on Stackoverflow here: http://stackoverflow.com/questions/12605816/sticky-flexible-footers-and-headers-css-working-fine-in-chrome-and-safari-but-n

    1. Yeah, table-heights are a tricky issue. However, I think I’ve found a solution to your problem. Check out my answer to your question on Stack Overflow.

      BTW: If you don’t care about the scroll-box and only want a footer that always stays at the bottom of the page, I’d recommend to simply use a div with position:fixed;bottom:0px; instead of CSS-tables.

      1. Thank you!

        I think a light dusting of JS is the way to get around it. Very succinct.

      2. I think I’ve found a way to achieve all of this in pure CSS using your ideas. Check out: http://stackoverflow.com/questions/12605816/sticky-flexible-footers-and-headers-css-working-fine-in-webkit-but-not-in-gecko/12622740#12622740

  6. nice Article. I always forget the power of table display, thanks for remind me :D

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

    1. Actually scratch that, I’ve worked out that IE 8 and 9 doesn’t seem to be able to select text with-in display:table-row.. An easy fix is to add a table-cell inside the row.. It’s a bit of divitis but it works:
      http://jsfiddle.net/WLPXV/1/

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

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

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

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

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

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

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

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

    1. Sorry, it erased the code i inserted, what i wanted to say is “when i add the script for adding jquery…”

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

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

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

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

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

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

    1. If you want to create a layout with multiple columns you might want to check out my “Holy Grail” layout grid: http://pixelsvsbytes.com/blog/2012/02/this-css-layout-grid-is-no-holy-grail/ I’m also using JS to adjust table-heights, although I don’t see the need to use JQuery here.

      Maybe Theo found a way how to fix the height without JS, but I still haven’t looked into his solution until now (shame on me). Anyway, here’s the link: http://stackoverflow.com/questions/12605816/sticky-flexible-footers-and-headers-css-working-fine-in-webkit-but-not-in-gecko/12622740#12622740

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

  12. Pingback: How to center horizontal table-cell - How-To Video
  13. 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.

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

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

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

      1. Thanks for replying. We ended up changing the behaviour of the footer on that website. But this one has your code: http://www.fredcarol.com.br/

        As you can see, in Chrome, there’s an empty space above and bellow the header and footer respectively. And now, with the updates, Firefox, Opera and Safari too! lol

        1. I just opened your example and the same problem is occurring in Chrome only. I’m really confused, now :D

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

    1. Hey Matt,

      Try my table-layout: fixed; trick mentioned below. I believe this will solve your problem.

  16. 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; }

  17. 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!

  18. Pingback: Sticky CSS footers: The flexible way | Eduardo Akio Fukunari - Blog
  19. Very cool. Just implemented this on a major international solution.
    Doing things with tables properties are cool. I also tend to use table layout fixed, for horisontal stuff, e.g. a timeline with fx a date with a fixed width, and the rest just adabt to fill the rest of the screen

  20. Awesome work. But I just noticed that on the new Microsoft browser Edge it doesn’t respect the Frame height 100%, not even you if set it as 100vh. Do you know how to fix this.

    Thanks!

    1. I haven’t investigated this so far, but if you aim for modern browsers I’d suggest to use a flexbox layout instead of this grid. It’s way more powerful and all modern browsers support it.

  21. The examples are not working for me in latest FireFox or Chrome. Put enough content in the content and the footer will disappear down.

    1. It’s not a bug, but the expected behaviour. If you want a footer that stays at the bottom of the viewport all the time, I suggest to use position: fixed in your footer CSS.

  22. Apparently not writing makes this not work (I Had !) I spent hours trying to fix this, i eventually stripped my website down exactly like your demo (except i left doctype) and i was like wtf!? The only difference was that doctype was there and when i put the ! mark in it work. WHAT THE HECK? The other thousand fluid sticky footers i tried probably would’ve worked if i had seen this! But thanks anyway!

  23. hi, i working on this and make a version compatible with Firefox/Chrome and center content, check this fiddle: https://jsfiddle.net/p9jbrx6L/1/
    download this example here: http://pastebin.com/9tQkD8W0

Leave a Reply to Treb Cancel reply

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