Saturday, March 10, 2007

The IE border-spacing workaround

Everyone knows these two HTML table tag attributes: cellpadding and cellspacing. And everyone hates the annoying necessity of these attributes in the CSS era. Well, developers, who has looked after what's up now about this issue, have learned that fortunately the cellpadding attribute is safely substitutable with the padding value of the table cells.

But what about cellspacing?

Cellspacing can also be omitted if you work with the border-collapsing model, because IE supports this model in CSS. (Or maybe not; we'll come back to this later.) Anyway, just put border-collapse: collapse in your table's style, and all the space between your table cells will be gone, and the adjacent borders will collapse to one simple border.

(For those of you who didn't fully get the picture, here is a nice illustration of the two border models.)

Problems will arise when you want to use the separated borders model. In this mode the CSS engine (browser) is expected to apply the td border styles separatedly to every single table cell, just as these were simple divs. We can think of this as the normal behaviour, and the collapsing model as a special case, if only because that the former is the initial (default) value in the CSS specs. When you're in the 'separate' model, you can control the space between your table cells with the border-spacing value of the table. You can set the horizontal and the vertical spacing.

But the problem is that IE doesn't support the CSS border-spacing attribute. Instead it puts a fixed 2px space between the cells. This is the point, where normally a developer gives up, becomes a bit melancholy, and puts back the cellspacing attribute into the HTML code. The conclusion: cellspacing can't be controlled by CSS (cross-browser).

Some good news

However, there is some consolation: generally you don't need that. Usually we only need to eliminate that bad looking space between the cells, and this can be achieved by CSS, even in IE. And the good news is that not only in the 'collapse' model but even in the separated!

Say, we want a table, in which all table rows have a red 1px bottom border, and a pink 1px top border (we want it to look a bit like buttons). 'Collapse' model is not an option now. This is a situation, where we have to use the 'separate' model with 0-width border-spacing between the cells.

For this the standard CSS code is as follows:
table {
border-collapse: separate;
}

td {
border-top: 1px solid red;
border-bottom: 1px solid pink;
}

It works in the standard compliant browsers, but what about IE?

That's a Feature, Not a Bug

Thankfully, IE is so buggy, that one bug helps to fix an other. So, what to do if I want to achieve a zero-spacing separating model? Exploit the bugs in the collapsing model! IE's border collapsing works fine, but magically gets switched off, if you give a 'position: relative' style to the table cells. If you do this, the browser jumps back to the separated model, width 0 cellspacing! Thx, Mr. Bug.
table {
border-collapse: separate;
border-spacing: 0;
*border-collapse: collapse; /* hack is needed for IE7 also */
}

td {
border-top: 1px solid red;
border-bottom: 1px solid pink;
*position: relative;
}

This way, you don't need any of those ugly HTML tag attributes, while working in either a collapsed, or a 0-cellspacing separated borders model. Have fun!

UPDATE

knakts noted in his comment that this workaround provides solution only to those cases in which the border-spacing value is zero. And I felt sympathy for him/her. Thus, as a matter of urgency, I researched another workaround, which brings us closer to the heaven.

Here it is:
table {
border-collapse: separate;
border-spacing: 5px;
*border-collapse: expression('separate', cellSpacing = '5px');
}

Still not perfect, because you can't differentiate vertical and horizontal spacing, but, as I said, one small step to the happiness.

knakts, don't be melancholic!

UPDATE 2 on 2009.05.05.

Check out this. An article about how to make it really behave like a one-time-running configuration, instead of the usual CSS expression behaviour with the well-known huge performance hit.

43 comments:

  1. OK -- this is a great post on an obscure topic -- thanks for the info!

    ReplyDelete
  2. Thanks a lot, this is great hack :-)

    ReplyDelete
  3. 1)Should I use both collapse and separate for class.table?
    and
    2)Is that "*" necessary in both
    *border-collapse: collapse;
    and
    *position: relative; ?

    Thanks
    David

    ReplyDelete
  4. Hi David,

    1. Yes, you should. Standard browsers will ignore the rules with an "*" before them.
    2. Yes, it's a necessary workaround for those rules which are not supported in either IE6 and IE7.

    ReplyDelete
  5. Interesting article. Unfortunately it is not solution for border-spacing other than zero. Now let me get a bit melancholy and put back up the cellspacing...

    ReplyDelete
  6. Thanks, the "expression" method worked. :)

    ReplyDelete
  7. I've been looking for days for a way to get more spacing between cells to simulate border-spacing in IE. This is the best solution I've found. Thanks very much!

    ReplyDelete
  8. Excellent solution!
    Thanks.

    ReplyDelete
  9. It is really helpful, thanks

    ReplyDelete
  10. Wow! Two days trying to figure out a solution to the border-spacing issue and all it needed was one line. This worked for me to make the spaces between cells look the same in IE, Opera, and Firefox.

    table {
    border-collapse: separate;
    *border-collapse: expression('separate', cellSpacing = '1px');
    border-spacing: 1px
    }

    So simple.

    When you know how. ;-)

    Thank you so very much.

    ReplyDelete
  11. Just what I was looking for! Thanks, Martin

    ReplyDelete
  12. I tried this solution and it didn't work. IE only said something about blocking active content, asked me if I wanted to allow some ActiveX thing, and when I said 'Yes' nothing happened. Still the default 2px separation.

    ReplyDelete
  13. @León, this is because JS is disabled on local machine by default in IE. You can test it with any script written in the HTML file. I bet you were working with a local file. CSS expressions are JS.

    After allowing that activeX thing refresh the page, then it'll work.

    You will not experience such problems if you work with remote files.

    ReplyDelete
  14. This post provided a very easy solution to a frustrating problem. Thank you for the info.

    ReplyDelete
  15. Fantastic workaround!!

    ReplyDelete
  16. Unfortunately, this work arround leaves you with a css not validated by the W3C CSS Validator.

    ReplyDelete
  17. If it's so important to you, I'll post a workaround how to make your workaroundish css validated by the w3c validator.

    ReplyDelete
  18. I used this, which validates fine. Hope it's useful to someone!

    HTML:
    < link rel='stylesheet' type='text/css' href='/css/basic.css' />
    < !--[if lte IE 7]>< link rel='stylesheet' type='text/css' href='/css/basic_ie_workarounds.css' />< ![endif]-->

    BASIC.CSS:
    table { border-collapse:separate; border-spacing:0; }
    /* ... etc ... */

    BASIC_IE_WORKAROUNDS.CSS:
    table { border-collapse:expression('separate',cellSpacing=0); }

    There's more CSS reset (browser unification) stuff in basic.css, and more IE workarounds (body->* font inheritance workaround, other) in basic_ie_workarounds.css too.

    Now I just need a working, validating, cross-browser block-level anchor element! :-) (Hint: this is impossible.)

    ReplyDelete
  19. In the above comment, there's a space between < and the following character, since this stupid blogging software thinks I want to inject HTML into the comment. So replace "< " with "<" before running the code.

    Also, if anyone is wondering whether 'separate',cellSpacing=0 really returns 'separate' and not 0, this little test reveals that both statements are run and the result of the first one is returned. Paste it in the browsers' URL line.

    Return value test:
    javascript:alert('x',cellSpacing=0);

    Run both test:
    javascript:alert('x',alert('y'));

    ReplyDelete
  20. and what if your CSS is "border-spacing: 2px 5px;"?
    In the IE-fix you can give only one number for cellspacing...

    ReplyDelete
  21. You haven't read the entire post. As for that, and AFAIK, different vertical and horizontal cellspacing is unaccomplishable in IE, either by HTML or CSS or other ways.

    ReplyDelete
  22. think i found a way to fix and diferentiate the vertical and horizontal spacing in IE.. :.

    just give the td a class, position it relative and move it left by -6px; it's kinda weird, but worked for what i needed to do... maybe u can use also td+td .
    A lot of hacks for one css though. I think i will use divs...

    table tr td.second {
    *position:relative;
    left:-6px;
    }

    ReplyDelete
  23. thanks!!
    PS u can also use - it's shorter ;)

    table.css_class {
    border-spacing: 1px;
    *border-collapse: expression('separate', cellSpacing = '1px');
    }

    ReplyDelete
  24. Perfect, a million thanks.

    ReplyDelete
  25. Thanks, appreciate this.

    ReplyDelete
  26. You are a friggin' genius! T H A N K - Y O U !

    ReplyDelete
  27. Not the perfect fix, but well worth mentioning in my blog about dynamic table creation.

    http://www.skewsme.com/observations4.html#tables

    ReplyDelete
  28. One and a half year later, still a very useful exploit. Thanks for sharing!

    ReplyDelete
  29. Anyone tested this on IE8? Anyway, big thanks, saves me the time I don't have to figure this one out.

    ReplyDelete
  30. IE8 fully supports CSS 2.1, so this is not an issue anymore.

    ReplyDelete
  31. I am having an issue with Firefox that I can't seem to find a hack for. Check out the Main vertical menu for www.wholesalewarrantyclub.com in Firefox and then in any other browser. It's working the way that I want it to in all browsers except firefox.
    The html looks like this:
    table border="0" cellspacing="2" cellpadding="0"

    and the images are a sprite. Firefox allows some of the background image to show through the 2px cellspacing...and I don't want that.

    ReplyDelete
  32. This is really good...it worked..but have another problem if anyone knows abt it. As per css if we use border-collapse: collapse; it will ignore empty-cells: show. how to achieve that? I mean for IE I am using the star hack provided here (*border-collapse: collapse;, *position:relative and empty-cells: show;) where as empty-cells is getting ignored because of *border-collapse: collapse;. I need both the properties any workaround?

    ReplyDelete
  33. This is exactly what I was looking for, thanks!

    ReplyDelete
  34. Excellent post. Just helped me too. Trying to make my ap the same in as many different browsers as possible even older ones like ie6 and have menu that looked fine in all but ie6/7. 3d effect with light border one side dark on other needed border-collapse:sererate but couldn't get the spacing on older ie's down to 0 till now. Have bookmarked your blog and will have a better look through soon to see what other handy snippets are there

    Cheers
    Andrew Blake

    ReplyDelete
  35. Thank you for sharing you provided me with a quick solution to the problem!!! Cheers x

    ReplyDelete
  36. Sweet, the expression worked for IE7

    ReplyDelete
  37. Thank you, the expression is fantastic for IE!

    ReplyDelete
  38. Awesome dude, how did you even discover this hack, hats off!!

    ReplyDelete
  39. Thanks for this great hint!

    Only drawback is, IE only understands px-values. em-values are not interpreted at all :-/

    ReplyDelete
  40. Thank you!! great quick solution for a obscure problem!!

    ReplyDelete
  41. thanks. this is very useful and it fixed the same problem on IE 9 for me.

    ReplyDelete