Earlier today I was attempting to style a table header when I came across a peculiar part of the CSS 2.1 spec. Here is what I was trying to create:
I has a table with a number of header elements and I wanted to style it such that each one would have 2px of gray border on the bottom and 2px of space in between each element. Simple enough, right?
After poking around for a bit with allowing table row elements to have margins, I decided it would be much easier to just put a right border on each element, 2px thick and solid white. Easy enough, right? Wrong! Here’s what I got:
It seems the bottom border would take precedence over the right border. But why? How could I override this? Eventually I stumbled upon the appropriate page of the CSS 2.1 spec, which explained everything (almost):
17.6.2.1 Border conflict resolution
In the collapsing border model, borders at every edge of every cell may be specified by border properties on a variety of elements that meet at that edge (cells, rows, row groups, columns, column groups, and the table itself), and these borders may vary in width, style, and color. The rule of thumb is that at each edge the most “eye catching” border style is chosen, except that any occurrence of the style ‘hidden’ unconditionally turns the border off.
The following rules determine which border style “wins” in case of a conflict:
- Borders with the ‘border-style’ of ‘hidden’ take precedence over all other conflicting borders. Any border with this value suppresses all borders at this location.
- Borders with a style of ‘none’ have the lowest priority. Only if the border properties of all the elements meeting at this edge are ‘none’ will the border be omitted (but note that ‘none’ is the default value for the border style.)
- If none of the styles are ‘hidden’ and at least one of them is not ‘none’, then narrow borders are discarded in favor of wider ones. If several have the same ‘border-width’ then styles are preferred in this order: ‘double’, ‘solid’, ‘dashed’, ‘dotted’, ‘ridge’, ‘outset’, ‘groove’, and the lowest: ‘inset’.
- If border styles differ only in color, then a style set on a cell wins over one on a row, which wins over a row group, column, column group and, lastly, table. When two elements of the same type conflict, then the one further to the left (if the table’s ‘direction’ is ‘ltr’; right, if it is ‘rtl’) and further to the top wins.
So there we have it…there is an order of precedence for border edges. While it seems relatively arbitrary, it is at least specified, which I suppose is better than nothing. This doesn’t exactly fix my problem though, now does it? In the end I copped out and just made the width in between the cells 3px and as per item 3, the white border took over.
I hope CSS 3 has some kind of mechanism to specify this (The CSS3 table module has yet to have a draft release). It seems like the ordering is relatively arbitrary and in rare situations where it does matter it’s worth being able to specify.