Using tables for layout purposes

Okay let's start off by saying using tables for layout purposes is a terrible idea - the web has largely moved on from that sort of thinking. The focuses on semantics and responsive design have become much more important than "that works" could ever be. The reduction in tables nested in tables nested in tables nested in wrapper tables is a huge step in a very positive direction in my opinion. However, this dodogy HTML did make some layout desires very very easy and some of those are quite awkward with sensible HTML and CSS. Apparently we need some sort of middle-ground compromise. Time for an example.

I recently came across a layout that is easy to do using tables but much less easy using semantic markup; basically a two column layout where the columns are equal height based on the longest content. In more detail this was a site with a left menu that should stretch all the way down to the bottom of the content. Easy with a table

<table class="wrapper">
    <tr>
        <td>
            <a href="thing1">Thing 1</a><br />
            <a href="thing2">Thing 2</a><br />
            <a href="thing3">Thing 3</a><br />
            <a href="thing4">Thing 4</a>
        </td>
        <td>
            <p>Main content</p>
        </td>
    </tr>
</table>

This "classic" way to do things makes our modern stomachs churn - but is does work, which is the problem. The fact that this kind of layout is awkward to do, in a compatible way, with modern techniques is a problem. Let's do what we should be doing and describe the content in markup

<nav class="left-menu">
    <a href="thing1">Thing 1</a>
    <a href="thing2">Thing 2</a>
    <a href="thing3">Thing 3</a>
    <a href="thing4">Thing 4</a>
</nav>
<div class="main-content">
    <p>Main content</p>
</div>

Now how do we make both of these elements behave the same as the table example? A few things we might try

.left-menu, .main-content {
    float: left;
    min-height: 100%
}

This doesn't work because floated elements can only have absolute heights so we get a stumpy menu.

.left-menu, .main-content {
    display: inline-block;
    min-height: 100%;
}

This sort of works but the content shows below the menu and can't be moved up without absolute positioning, a responsive site nightmare.

.left-menu, .main-content {
    float: left;
    min-height: 3000px;
}

Getting a little desperate with this one, which does work if we don't care about random scroll bars and high chance of breaking. There is always flexbox - but that is lacking IE9 support, which we're assuming we need for the sake of this post.

One thing that will work perfectly is to make this behave as if it were a table.

body {
    display: table;
}

.left-menu, .main-content {
    display: table-cell;
    vertical-align: top;
}

body::after {
    display: block;
    content: '';
    height: 100%;
    min-height: 100vh;
    width: 0px;
}

The pseudo element is needed to make the columns expand to the bottom of the page even if the content is not long enough - for some reason min-height on the actual elements does not seem to work.

The point of this post is that I'm not sure how I feel about this - using table features for layout still feels wrong but then the markup describes the content. Perhaps the disgust at the idea is mostly related to the HTML and not so important when using CSS? Perhaps there should never have been a display: table property? The main argument from the anti-table movement was that the stuff being placed inside them was not tabular data (you couldn't thing of headings for each column) - the CSS solution does not violate that so I think we're okay to use it. A very grey area.

Post a new comment