Updated in Feb 1 2017

The problem is simple: I want to add a footer to the HTML web page. However, some page has only a few lines of text, while some page can be very long.

Thus, the footer should be flexible:

  1. It should stay at the end of page for the first case, and only show up when you scroll to the very end.
  2. It should stick to the bottom of the current view for the second case, despite how short the actual text area is.

Here is how I tried to fix this problem.

Try #1: CSS position: fixed

.footer {
    position: absolute;
    width: 100%;
    bottom: 0;
}

However, it doesn’t work uniformly for both short page and long page.

Try #2: CSS @media

I tried to use the @media rule to take the window size into consideration. However, @media is static and can’t deal with the dynamic changes introduced when users squeeze/stretch the window.

Solution #1: jQuery

We can get the height and width of document and window easily with $(document).height() and $(window).height().

Since the document contains all elements of the page, including footer, so we can simply compare its height with window’s height. After that, we can decide whether or not to add CSS code to footer to make it fixed at the bottom of window.

function relocate(){
    var windowHeight = $(window).height();
    var docHeight = $(document).height();
    if (docHeight <= windowHeight){
        // The document can be fitted into the frame
        $(".footer").css({
            "position" : "absolute",
            "bottom" : 0,
            "width" : "100%"
        })
    }
}

relocate();

However, the script will only be executed once at loading. If the user resizes the window while browsing, we need to adjust responsively. So I wrapped the original code in resize method of window to catch the resizing event made by user.

// If the document is short enough, the footer will be fixed at the bottom of page.
function relocate(){
    var windowHeight = $(window).height();
    var docHeight = $(document).height();
    if (docHeight <= windowHeight){
        // The document can be fitted into the frame
        $(".footer").css({
            "position" : "absolute",
            "bottom" : 0,
            "width" : "100%"
        })
    }
    else
        // Restore
        $(".footer").css("position", "relative");
}

$(window).resize(function(){
    relocate();
});

However, another problem exists! When I full-screened the webpage, the window’s height change was not caught as a resize event.

A hack to fix this is to trigger the relocate periodically.

// If the document is short enough, the footer will be fixed to the bottom of page.
function relocate(){
    var windowHeight = $(window).height();
    var docHeight = $(document).height();
    if (docHeight <= windowHeight){
        // The document can be fitted into the frame
        $(".footer").css({
            "position" : "absolute",
            "bottom" : 0,
            "width" : "100%"
        })
    }
    else
        // Restore
        $(".footer").css("position", "relative");

    setTimeout(relocate, 100);
}

relocate();

Solution #2: Flexbox

Credit: Minsheng Liu

Demo source code (on JSFiddle as well):

<!DOCTYPE html>
<html>
<head>
    <title>Footer Demo</title>
    <link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>
<section class="content">
    <h1>Content</h1>
    <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
        tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
        quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
        consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
        cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
        proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </p>
</section>
<div class="footer">
Footer
</div>
</body>
</html>

And here is index.css:

.content {
    flex: 1;
    max-width: 500px;
    margin-bottom: 3rem;
    margin: auto;
}

.footer {
    text-align: center;
    background: lightgray;
    height: 3rem;
}

body {
    margin: 0;
    display: flex;
    min-height: 100vh;
    flex-direction: column;
}

You can copy the content several times to observe the position of footer.This method uses the flexbox:

The CSS3 Flexible Box, or flexbox, is a layout mode providing for the arrangement of elements on a page such that the elements behave predictably when the page layout must accommodate different screen sizes and different display devices. For many applications, the flexible box model provides an improvement over the block model in that it does not use floats, nor do the flex container’s margins collapse with the margins of its contents.

So in the above demo, body is a flex container. By setting body’s flex-direction to column, flex items (.content and .footer) are stacked vertically. And note that .contnet has a margin constraint margin-bottom: 3rem;, which makes it leave exactly that much space for footer.

Misc

There is a pretty nice Vanilla CSS solution, which is not ideal but still workable.