Devil's Advocate: in defense of table-based layouts

2/21/05

I gotchyer CSS right here, baby.

I’ve been designing web pages for a long time. I — seriously — remember how exciting it was when it became possible to specify the background color of a web page, and we no longer had to design everything around Netscape Gray. I remember all of us at the Tripod office gathered around the monitor oohing and aahing over this amazing “gif89” thing the guys at Razorfish had done; later that day Nate went and looked up the spec and hacked together a perl script so we could make animations too. The <center> tag rocked my world when it was introduced. Good times.

So, like everyone, I’ve spent a lot of time learning all the hacks and tricks and workarounds to get a layout functioning in a reasonably broad span of browsers — and then unlearning those hacks and tricks and learning the new ones as each new layer of technology got added on to the web. Bare paragraph and header tags gave way to table-based layouts. Background images on table cels added a new level of design flexibility. Everybody made a brief wrong turn into ActiveX and Director or Flash-based designs, then backed out when CSS came along. Now all the cool kids have a brag-bar of links at the bottom of their pages, announcing their strict XHTML, CSS-only, 508, not-gonna-use-a-table-even-for-tabular-data-dammit dogma.

I use CSS, obviously. Being able to change the font size and leading throughout a site by tweaking a single line of code is huge. Pixel-level control over margin and padding is an absolute lifesaver. And I no longer have to pull out this monster chunk of code, which used to be part of my standard arsenal:

<table border="0" cellpadding="0" cellspacing="0" width="200" height="200">
  <tr>
    <td width="35" height="35" background="/img/content/leaf_tl.gif">
      <img src="/img/spacer.gif" width="35" height="35">
 		</td>
    <td width="165" height="35" background="/img/content/leaf_t.gif">
      <img src="/img/spacer.gif" width="35" height="35">
 		</td>
    <td width="35" height="35" background="/img/content/leaf_tr.gif">
      <img src="/img/spacer.gif" width="35" height="35">
 		</td>
  </tr>
  <tr>
    <td height="165" width="35" background="/img/content/leaf_l.gif">
      <img src="/img/spacer.gif" width="35" height="35">
 		</td>
    <td width="165" height="165" bgcolor="#FFFFFF" align="center"> Hi, mom! </td>
    <td width="35" height="35" background="/img/content/leaf_r.gif">
      <img src="/img/spacer.gif" width="35" height="35">
 		</td>
  </tr>
  <tr>
    <td width="35" height="35" background="/img/content/leaf_bl.gif">
      <img src="/img/spacer.gif" width="35" height="35">
 		</td>
    <td width="165" height="35" background="/img/content/leaf_b.gif">
      <img src="/img/spacer.gif" width="35" height="35">
 		</td>
    <td width="35" height="35" background="/img/content/leaf_br.gif">
      <img src="/img/spacer.gif" width="35" height="35">
 		</td>
  </tr>
</table>

…every time I want to decorate every edge of a block of text:

Hi, mom!

…all I have to do is use something like alistapart’s “sliding doors” technique; make one really wide graphic to form the top, left, bottom, and middle borders, then cap it with a small graphic on the right. Unless I need the thing to be able to scale to fit arbitrarily large chunks of content. In which case I’ll need to make a mother-huge background graphic nailed to the top left of the content div for the top and left edges, and nest that div in at least three others: one to hold the top right corner and right-hand edge, one for the bottom left corner and bottom edge, and a final one for the bottom right corner. And I’ll have to avoid using transparent backgrounds, as I did in the table cel example above, because due to the way the nested divs overlap you’d see the wrong graphic peeking through from behind the transparent parts. And along the way I’ll have to build in a bunch of box-model hacks and @import tweaks to accommodate the different way certain ahem browsers choose to interpret CSS.

So wait a minute.

The big benefit of strict CSS-based design is supposed to be that it simplifies your code, and that it separates your presentation layer from your content. But for this example — which isn’t some oddball weird example, it’s a basic design need — the code isn’t simpler (all we’ve done is moved the complexity from the html into the CSS) and it isn’t separate from the presentation (because of all those extra node hooks you need to hang the extra graphics on). It’s not nearly as robust as the table example, because of the transparency problems and because no matter how big you make that main graphic, there’s always the risk that some bit of content won’t fit and you’ll have to make it even bigger. And because of that huge graphic, it’s a bandwidth hog compared to the tiny little 35-pixel table graphics. Even if all the browser incompatibilities were fixed and all the box-model problems comfortably boxed in, that problem alone would make the table code superior to the CSS-based version, in many situations.

Maybe you just don’t know what you’re doing.

Possible. I’ve internalized all the tricks of the table-based trade, so much so that I don’t even notice that I’m using them anymore; the CSS problems still bother me because I’m not used to them yet. But this guy clearly knows what he’s doing, and his example suffers from the same scaling problems, and isn’t any cleaner semantically than mine is. (He depends on content nodes, such as that <h2>, instead of bare <div>s, to hang his CSS hooks on, but same difference.)

I’ve put a lot of effort recently into trying to build strict XHTML websites. Because, hey, I want to be one of the cool kids. And every time I get stuck, I google. Because that’s how the cool kids do it. And often as not I find out that whatever it is I’m stuck on is either impossible in pure CSS, or is much, much more difficult than it would be using a table. (This is my current favorite example: an unbelievable amount of effort and skill poured into reproducing exactly what a three-column table does, but without using a table.)

So while the problem may be me, it’s also me and a whole lot of other people. Designing strictly-compliant sites feels like working with one hand tied behind my back: I keep finding myself thinking “I know exactly how I could do this with a table, but that way would be Wrong™.” That’s fine if all I’m going for is bragging rights, but it’s difficult to justify it to a paying client.

But you’re mixing your presentation with your content!

Except, no, I’m not. On this website, my content layer is a SQL database full of raw markdown-formatted text. My presentation layer is a set of Template Toolkit files. I seriously can’t think of the last time I worked on a website that wasn’t using some sort of serverside templating system, whether it’s XSLT or a template kit or what have you… If you need to redesign the site, you just redesign the templates. In these situations, switching over to fully CSS-based layout wouldn’t really make site maintenance any easier; it just moves it from the serverside (which you can control) to the clientside (which you often can’t.)

Meanwhile: most real-world CSS design examples need so many extra node hooks that they can’t really be called separate from the presentation. (When CSS Zen Garden eliminates all those redundant <span> tags, all the “extraDiv” containers, and removes the content-specific “id” attributes throughout, then we can talk about how CSS separates presentation from content.)

But you’re messing up the semantic web!

What semantic web?

So, what, you think CSS is bad?

Heck no. (And this strawman Q-and-A style of writing is getting on my nerves, so surely it must be getting on yours, so I’ll stop it now.) CSS is a wonderful tool, it opens up tons of possibilites that aren’t available any other way. But — in my experience, and with current browsers — while it’s excellent for small-scale bits and pieces and for text styling, it generally blows for real-world full page layouts. CSS2 will improve things, when it’s universally supported. And I’m sure CSS3, with its 100%-DWIM styling layer, will be the best thing since sliced bread, and will work perfectly and will be supported universally. In the meantime, I’ll keep using whatever tool works best for the job at hand.