Dynamic layouts with adaptive columns

Posted on December 31, 2005

Screen sizes are becoming increasingly diverse as mobile computing increases. While wide-screen formats are becoming more common-place in desktop monitors, with horizontal resolutions beyond 2000 pixels, mobile devices rely on much smaller portrait format screens, and run much less capable clients than their desktop cousins.

Designing for multiple devices is all about future-proofing. It's highly unlikely that mobile clients make a significant impression on your log-files, if any. However, it is undeniable that they will do in a couple of years from now.

It makes sense to develop sites now that'll need extensive coding two years down the road. The internet has proven to be a long-lived medium; temporary sites hang around for years, "coming soons" abound. Here are a couple of techniques that move towards designing backwards-compatible, future-proof documents for multiple devices, with an example of an adaptive document layout.

Bottom-up design

Bottom-up design means designing for the lowest common denominator. Make sure that all target clients have access to the information and navigational elements being offered.

Use semantic mark-up.

Format using standard HTML elements. Use lists for menu items. Use h1, h2, h3 for headlines and sublines. Basically, avoid "divitis" - using divs where there is a perfectly applicable HTML element. A div (or span) element tells us nothing about the meaning of it's content, unlike an em element. HTML clients without CSS capabilites will still be able to translate this meaning to the user (accessibilty zealots: think screenreaders).

Use well-formed XHTML mark-up.

Even if your document is being delivered using a text/html mime-type (and the chances are good that it is, even with an xhtml DTD), it makes sense to use well-formed XHTML, and to avoid deprecated HTML 4 elements. Clients will interpret it as HTML with a handful of odd closing tags. When the time comes the mime-type can be changed without having to adapt the bulk of the mark-up. When exactly the time will come is of course open to debate. Explorer 7 won't include support for the application/xhtml+xml mime-type.

Separate style from content.

Once the basic mark-up is defined and is making sense in a stand-alone context, add all the style you want using CSS. Keep it as simple as possible, which doesn't mean keep it plain.
Avoid hacks - they may cause you headaches later.

Graceful enhancements.

A lot has been said about gracefully deprecating scripting recently. This basically means using non-intrusive methods to add behaviour to a site; the functionality of the page won't break when javascript isn't available.

Using a bottom-up aproach we are coming from the other direction, so I prefer to call such methods "graceful enhancements". The key technique here is javascript replacement using the DOM. We've got our semantic content styled using CSS, now it's time to add those sexy extra features for those who can handle it. An example of this is my flash-replacement slideshow with Javascript & XHTML - a basic XHTML page of images and captions is replaced by a flash image viewer application using the same data, if the client is capable of showing it. If you're not doing it yet, use Bobby van der Sluis' excellent Unobtrusive Flash Objects to embed your flash. It'll keep your mark-up sleek and lean, and it practically forces you to provide alternative content (you need to have something to replace in the first place!).

Which brings me back to my original point about screen resolutions. Here's my version of an adaptive layout using XHTML, CSS and Javascript. The mark-up is semantic and (more-or-less) accessible. Certain content is hidden using CSS when considered redundant (the "main menu" heading) - the styling should indicate that it is the main menu. If javascript is available, the layout will attempt to adapt itself to the horizontal screen resolution.

The content is split into one "row" div containing three "column" divs. These elements have no semantic meaning and are used only for layout, and have no effect on the layout when CSS is disabled.

If CSS is enabled, but javascript disabled, each "column" takes the whole of the available width of it's containing element, the "row" div, resulting in 3 rows. However, if javascript is enabled, the "columns" place themselves according to rules defined in the following javascript:

<script type="text/javascript" src="adaptLayout.js"></script>
<script type="text/javascript">
//<![CDATA[

adaptLayout.addRow(
{
	container : 'row',
	columns : new Array (
			{  id : 'content',  mw : 300  },
			{  id : 'content2',  mw : 300 },
			{  id : 'menu', fw : 250 }
		)
}
);

//]]>
</script>

In adaptLayout.js an object called adaptLayout is created with the following public methods: init(), addRow(Object),

addRow passes an object that defines the row and columns. "container" is the id of the containing div. "columns" is an array of objects containing the column information. "id" is the id of the column. The second attribute is either "mw" for a minimum pixel width, or "fw" for a fixed pixel width. A minimum width column will share the available horizontal space equally with other minimum width columns if it's portion of that width is above it's designated minimum. Otherwise the last column in the row is "wrapped" to a new row. Fixed width columns, as you would expect, maintain a fixed width, unless they are alone in a row; then they take up all available space.

The adaptLayout is initialised using the init method, which adds on onresize handler to the document.

<script type="text/javascript">
//<![CDATA[
	adaptLayout.init();
//]]>
</script>

Using this technique we can prevent really, really wide text-columns on high resolution monitors while making the best possible use of the avaiable screen real-estate. Here's the javascript.