Tuesday, January 27, 2009

Pragmatism

I've recently been working on implementing a two column layout for Jazz web UIs (reg req'd). I could easily update our current layout's images and styles and be done with it, but while I'm restructuring, I want to clean up some of our current layout's problem areas. Currently, we've got the following "features":

1) Two column layout with equal height columns (one fixed width, one fluid width)
2) Drop shadow and gutters on either side of the layout
3) Sticky footer; make the layout stretch the full height of the window with a footer at the bottom.

CSS hackers everywhere know that these three requirements are tricky to achieve together. The sticky footer was achieved by adding a page wrapper div with 100% height, followed by a footer div with a negative top margin equal to its height. The columns inside the page wrapper were then stretched down to the footer using the One True Layout hack (large negative bottom margin with large positive bottom padding).

Unfortunately, this hack required overflow: hidden on the wrapper, which killed off the possibility of enabling horizontal scrolling on the layout (i.e. what if a table has a zillion columns and is wider than the screen? Sorry, it gets chopped at the edge).

To make things worse, even if I used another mechanism for the equal height columns, DIVs don't expand to fit their contents, so the wide table would just overflow out of the layout, which is ugly.

Another problem area had to do with floats. To achieve the two column layout, I floated one of the columns left, and allowed the other to fill the remaining space (with overflow: hidden to give it its own block formatting context so that the columns drew beside each other instead of overlapping). Unfortunately, anytime the right-most column was forced wider than its auto width, it would wrap below the left column. There were various ways to mitigate this wrapping, but they all precluded horizontal scrolling.

As far as I know, there is no CSS only solution to achieve all of my requirements while mitigating the aforementioned problems (if there is, I'd love to hear it). So I set out to find a happy medium, which led me to tables.

I can hear the groans from the CSS elite (What's your CSS level?). Table layout!! NOOO!! But hear me out.

Tables are expand-to-fit! They're the only HTML element that does this. So I'm using this property to achieve my horizontal scrolling. The great news is that tables expand even if they are set to overflow: hidden, so my One True Layout hack will still work for the equal height columns. I lose my sticky footer, but I can easily achieve that with some simple onload javascript logic that sets the height of the table's one and only cell.

But that still leaves my column wrapping problem. Horizontal scrolling is moot if the column wraps before it scrolls. So how do I fix this? I could split my table into two columns, but my willingness to rely on tables only goes so far. What other ways are there to put divs side by side? For that, I turned to display: inline-block.

Display: inline-block causes the element to generate a block box (like display: block), but to flow relative to its siblings using an inline formatting context (i.e. side by side like display: inline). To make this work on IE, I had to use spans instead of divs, but that's easy enough. By adding white-space: nowrap to the parent of these divs, all wrapping is nixed, and the table cell expands as it should when content forces out the side.

Sounds too good to be true, and it is... Inline-block elements do not fill their available width as block elements do, so inner divs would only be as wide as their contents force them to be.

To fix this, I had to apply a fixed width to this column using JavaScript, and register a resize handler to update the width when the window changes. This is no problem in Jazz Web UI land since these pages require JavaScript to even work (async code loading and dojo-based UI widgets). Even with the fixed width, the table continues to encapsulate overflowing contents.

Take a look at the final result: http://twitpic.com/17wdi

So is it bad that I'm using a table? I don't think so. It's important to be pragmatic in web development. If an element has a property that you need, use it!

2 comments:

Unknown said...

I say a table a day keeps the layout at bay

Seth said...

Nicely done