C and S Design.
Search Friendly Programming and Design




Javascript Code Articles

Coming to a sticky end or is it a Sticky Footer?

See the demonstration

A thread at Webmaster-Talk prompted another article, this one on how to place footer text at the bottom of the browser window if the body content is shorter than the available window "whitespace" or if the content fills the window allow the footer text to be positioned under the content, where it would normally be in the document flow.

One problem with this idea is it cannot be done using CSS 2 directly, so we need to use some client side scripting to achieve it. Here is where we hit our first problem.
browser viewport The area that concerns us is the browser viewport. This is the area of the browser window the pages have to fit into. The height is the section between the bottom edge of the top section which may include any add-ons, toolbars, menus, etc and the top edge of the bottom section including status bar if visible. The width is between the left and right edges and has to allow for sidebar add-ons, scrollbars etc. So for any given resolution the area is unlikely to be the same on any browser on one machine never mind on different machine for different users, then of course users on high resolution display do not always have their browser window maximised.
To compound this dilemma there does not exist a single cross-browser method to return the viewport height and width, and to add to the woes, Internet Explorer does different things depending on which "mode" it is in! More on this in the Quirksmode article on Viewport properties

"Stick" the footer

Making a footer "stick" to the bottom of the viewport with CSS involves some "hacks" to make things work as intended. One example is at A LIST apart with Exploring Footers. Personally I prefer NOT to use CSS "hacks" to workaround browser "features" because you never know when they will be fixed and the "fix" breaks and makes things worse. So devising a scripting method that degrades gracefully in browsers and user agents without javascript is preferable.

First off we need to get the viewport height. As mentioned earlier, there are some "issues" getting this metric but with a little bit of editing to a quirksmode script (See link above) we have a function that will work across all browsers and return the correct value.
This function will be called by the second function needed to set the position of the footer element

Function getWindowHeight

function getWindowHeight() {
if (self.innerHeight)
{
	return self.innerHeight;
}
else if (document.documentElement && document.documentElement.clientHeight)
{
	return document.documentElement.clientHeight;
}
else if (document.body)
{
	return document.body.clientHeight;
}
}

The second function ( setFooter() ) is what sets the text block position, there is no need for any use of absolute positioning, which brings along it's own legacy of problems with IE, and no "hacks" to be applied.
It is simply a case of calculating where the top of the element should be in relation to the bottom of the viewport and setting it in the element style. The style should be set to use the document flow when first rendered and the script is then called once the page has loaded.
This simply gets around any non-javascript enabled user agent by leaving everything as it is initially laid out.

Function setFooter

function setFooter() {
var ch = document.getElementById("main").offsetHeight;
var wh = getWindowHeight();
var f = document.getElementById("footer");
var d = document.getElementById("design");
if (ch < wh) {
	f.style.top = (wh -ch) - f.style.height +"px";
	d.style.top = (wh -ch) - d.style.height +"px";
	} else {
	f.style.top = 0+"px";
	d.style.top = 0+"px";
	}
}

In the setFooter function published here, there are two elements referenced, "footer" and "design" . The reason for this is, the pages on this site have two blocks of text as an include, so for the purposes of this demonstration both of the blocks are moved together.

Script Walkthrough

var ch = document.getElementById("main").offsetHeight; Initialises a variable and gets the height of the "main" element, which is the "wrapper" for the pages. If the design of the page has no wrapper element, var ch = document.body.offsetHeight; could be used instead.
var wh = getWindowHeight(); Calls the function to return the inner height of the viewport.
var f = document.getElementById("footer"); and var d = document.getElementById("design"); get the two elements objects as variables.
if (ch < wh) {. Tests to see if the content height is greater than the window height, if so calculate and set the top position of the element (window height - client height) - element height.

The } else { part of the script is only really required here for the demo, as the top requires resetting when the test elements are hidden and reduce the height of the content, normally this would not be required as a real visitor to the page would not even care if the footer moved or not.

The final step is to add a call to the setFooter() function.
This can be done in the <body onLoad="setFooter()"> event or as I have in a script block after the closing </html> tag

</html>
<script type="text/javascript">
setFooter();
</script>

This is done purely to ensure the page is fully loaded before the script is triggered.

Why Absolutely no Negatives

Using the calculated top method here I avoid having to do any position:absolute or negative margin jiggery-pokery which can give unwanted results in some browsers.
Also the position and flow of the document elements is left alone unless the content height requires that the footer should "stick". This leaves the page accessible and useable by non javascript agents, if the js doesn't trigger, the footer will simply fit in it's natural position under the content.


Valid HTML 4.01! Valid CSS! copyright © C and S Design 2004 - 2005
Website Design and SE Friendly Coding C and S Design