Interesting CSS Quirks: Border-spacing

By Alex Walker

I came across a CSS peculiarity recently that had me scratching my head, so I thought it was worth popping in a little post here for future Googling head-scratchers.

The WSG mailing list gets a lot of CSS layout questions sent to it and last week I noticed this query. Tee wanted to visually reproduce the table layout shown below without adding extra wrapping DIVs or other non-semantic markup.

Example table layout

It’s not quite as simple as it looks.

Anyway, playing around my approach, I came across a CSS property I’ve rarely seen in use: border-spacing.

Now if you’re not super familiar with border-spacing, it’s essentially a better version of the old ‘cellspacing’ table attribute (i.e. <table cellspacing="3px" ..) , and controls the space *between* your table cells. Of course, if you set the table’s border to collapse (i.e. border-collapse:collapse;) there *is* no space between your table cells, so setting border-spacing becomes redundant.

The key advantage that CSS’s border-spacing has over HTML’s cellspacing (besides cleaner markup) is it allows you to set different horizontal and vertical spacing widths — seemingly perfect for creating the 5 pixel row separations required in the example. Cellspacing only accepts a single value.

Guessing the CSS, I didn’t get the result I expected when I tried (try for yourself):

table#grid {
	border-spacing:  5px 0px ;

Border-spacing in actionCounter-intuitively to the way margin, padding, border and every other CSS property I can think of operates, border-spacing asks for it’s horizontal value before it’s vertical value. Strange.

Other points to note with border-spacing:

  • You aren’t able to assign different top, bottom, right and left values. This makes sense if you think about it, as we’re actually talking about an attribute of the TABLE, but I think it’s easy to trick yourself into thinking it’s part of the TD — it wraps around the TD borders after all.
  • Support is perfect in all modern browsers, but old IE6 & 7 don’t support this property at all.
  • shmlco

    “…below without adding extra wrapping DIVs or other non-semantic markup.”

    Okay, there are times when being a purist just doesn’t make sense, and this is one of those times. Forgoing extra markup, ids, and classes makes things harder, not easier. Worse, it assumes that the markup needed for your current layout is ALL of the markup that you’ll ever need.

    A design decision that will almost always will come back to haunt you, usually during your next site redisign meeting. “We have to edit every page on the site? Why???”

    Hell, even the holy grail of CSS design, CSS ZenGarden, adds extra divs and spans to the page as “hooks” for future designs.

  • AlexW

    @shmlco Agreed in principle. My personal interest was the challenge.

    However, personally I would put adding extra IDs and classes in a separate class to adding extra DIVs or SPANs. I can’t think of many case where I’ve thought ‘gee I wish I’d never added that ID’, but there have been times where, say, trying to figure out if a troublesome gap was inherited margin or padding has been a pain. Keeping the construction simple makes bug swatting easier.

    But, yeah, there is a point when you bow to practicalities.

  • justin

    and since ie7 doesn’t support this…it’s completely impractical.

    sad but true

  • barrybloye

    Counter-intuitively to the way margin, padding, border and every other CSS property I can think of operates, border-spacing asks for it’s horizontal value before it’s vertical value. Strange.

    background-position (and the background shortcut) also uses values in an x,y order.

    It seems to me that the difference is that these use x,y values, whereas properties like margin are shortcuts for -top, -right, -bottom and -left values.

    @shmlco CSS Zen Garden’s founder, Dave Shea, admits that the markup used was never intended to be a good example, and in hindsight could have even been much slimmer. At the time (2003?), he just wanted to create a test case to attract designers to CSS and wanted to provide plenty of hooks to allow as much flexibility as possible.

  • squig

    Really useful post – thanks.

  • Fred P.


    There’s a hack on IE 6 & 7:

    table {
      border-spacing: 0; /* Gecko, Webkit, IE 8 */
      ~border-spacing: expression(this.cellSpacing=0); /* IE 6, 7 */
  • Stevie D

    and since ie7 doesn’t support this…it’s completely impractical.

    Not at all. You just accept that the design will look slightly different on IE7, it’s hardly the end of the world.

  • shmlco

    Justin said, “…and wanted to provide plenty of hooks to allow as much flexibility as possible.”

    Which was my point exactly. Using the absolute bare minimum of markup means you’re designing for the situation as it exists now, and not accommodating future needs.

  • AlexW

    @barrybloye — that is a good point. I hadn’t thought of that, but I’ve always felt the order of background-position seemed backwards too.

    @Stevie D — it’s obviously a case-by-case thing, but yes, in a situation like the example, I think I’d prefer to leave IE6+7 slightly different. After all we are only talking about some extra vertical white spaces and I don’t think it’s visually obvious they aren’t designed to be there.

    @shmlco — I added .last and .first classes to the TDs because they’re always likely to be useful until IE6 dies and we can use more advanced selectors. But this is a programmed looped table section. If some future redesign desperately needed more markup hooks (divs and spans), adding them in would be no huge issue. rather than trying to second guess a design that may never happen.

    Modern CSS generally requires less hooks to do the same work (multiple backgrounds, etc).

  • AlexW

    @Fred P — those expressions can be handy but in this case maybe not quite right. We ideally need differing cellspacing widths for x and y and I’m pretty sure expressions won’t help us (correct me I’m wrong).

    Did a little research, and there are some performance questions associated with expressions too. Apparently they get triggered on every mouse movement, so the browser can end up be deluged by thousands of events every second. There are a few workarounds but sounds like you’d want to be carefulish before using them.

Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in JavaScript, once a week, for free.