fighting the tr

css styling restrictions

June 29, 2011
in: css / musings

How can it be that with several years of intense front-end experience, you can still get stuck implementing the most trivial of things from time to time. Not too long ago I okayed a design that seemed simple enough, but once I sat down to implement it (keeping in mind IE6/IE7 support) I hit a wall pretty quick. I've questioned the usefulness of html restrictions before (html headings and the footer attribute), the same argument can be made for restrictions on css properties.

table rows

The requested design wasn't anything special really. It was a simple product list where each product was presented as a horizontal block. Whether this warrants a table structure or not is a discussion I'll try to avoid here, the thing is that the html was already there (and implemented), so everything had to be done using css only. When I first saw the design I figured it wouldn't be too hard to separate the tr elements from each other, but once I tried to implement it cross-browser I lost a lot of time trying out different options. None of them wielded good results.

The design exercise was made a little harder by two extra conditions. First of all it should be possible to add a drop-shadow to each product box, secondly the list should be able to exist on a gradient background. These conditions don't show up on the design above, but the site was set up to be themable to a certain degree, so we had to take those possibilities into account.

Using borders to fake the effect was not really an option, considering the uncertain background color and browser support for older versions of IE. Faking the gap using background-images on the td elements inside was equally unsuccessful, as you ended up screwing the inner td borders. The only way to do this was to create an actual gap between the tr elements. For that we usually define a margin, but margins don't work on tr elements.

A short how-to

table {border-collapse:separate; border-spacing:0 10px;}

The clean way to do this is by using border-spacing. Apparently there are a few subtle nuances between the border-spacing and margin properties, but broadly speaking they create a very similar effect. It's important to note that the border-spacing only kicks in when defining a border-collapse:separate though, so don't forget to do that first.

The line above creates a vertical gap of 10px between the cells, without creating any horizontal gaps (0px). The inner td borders need a little fiddling with (:last-child to the rescue), but the line above pretty much does the trick. Sadly IE8- support is crap. You can add a position:relative; on the td elements for less crappy rendering, but that's about as far as you'll get. Not good enough.

As a side note, you might have noticed that you need to set the border-spacing property to 0 10px, where a margin would be set as 10px 0 to created vertical padding. Heh.

table, tr, td {display:block;} tr {margin:10px 0;}

A dirtier, but ultimately more browser-proof way of doing this is by removing all table-specific display modes from the table elements. Just set everything to block and you can start using your margins on the tr element.

That's fine for creating the needed space between the product blocks, but creating an equal height effect for the td elements becomes a whole lot more difficult than it should be. So while this method is fine by itself, you're probably setting yourself up for some pretty messy css when you start styling the inner elements of the product block.

what this is really about

I understand that display:table-row and display:block are two different display modes. But in the end they both result in a single rectangle form that would (and should) interpret properties like margin just the same. If a tr can handle a drop-shadow, why can't it make a simple margin work (and/or why does it need a specific property that's far more obscure than margin and uses a reverse shorthand?).

There are historical reasons (border-spacing was created to replace the cellspacing attribute on a table), but in the end I still get the feeling that sometimes html and css are a little over-engineered and too focused on backwards compatibility. In the end all these restrictions amount to very little. They might seem logical at first, but five years down the road people still run into use cases where certain restrictions are simply blocking the way to easy development.


I must say that things are definitely improving (remember how they lifted restrictions on the footer element), but it would still be nice to see a more self-aware shift in mentality.

I'm all for best practices, but restrictions built into html and css that try to enforce these best practices often turn out to be counter-productive. Blocking margins from tr elements is one of those, ruling out the use of divs in headings is just another random example. At some point these restrictions might've seemed like a good idea, but the web is vast and infinite and there is just no way of foreseeing all use cases. Especially not those five years into the future.

To style the simple design above, I spent way too much time cursing at the restrictions of css, without knowing why they were even there. It's not like I was trying to do something extremely creepy or cutting edge, I just needed a little space between the tr elements in a table.