Styling table columns with nth-child()

Posted by on

Tables in HTML are dead. Well, mostly. Sometimes you actually have tabular data that you wish to show on a website, and in that case the <table> element is obviously still the best choice.
One problem that I often encounter is that while you can style table rows quite easily with a single class per row, styling columns is harder.

Here's a random example table from a site I've been working on.

Month Credits Earned Dollars Earned
June 2012 2,054 $133
July 2012 1,580 $89
June 2012 3240 $187

Classes

Now say you want to align the columns with numbers to the right and give the final column a different background color. One of the ways to do this is to use classes on each of the table cells.

This isn't a bad solution per se, especially if you use semantic classes and not just class="align-right", but on big tables you end up with lots and lots of classes horizontally (for every cell that you need to style) and vertically (for every row, repeat the cells and their classes). I don't like that.

The <col /> element

Another solution is to use the <col /> element. By defining the columns in your table you can add CSS hooks to it in this way:

<table class="sales">
  <colgroup>
    <col class="month" />
    <col class="credits" />
    <col class="dollars" />
  </colgroup>
  <thead>
    <tr>
      <th>Month</th>
      <th>Credits Earned</th>
      <th>Dollars Earned</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>June 2012</td>
      <td>2,054</td>
      <td>$133</td>
    </tr>
    <tr>
      <td>July 2012</td>
      <td>1,580</td>
      <td>$89</td>
    </tr>
  </tbody>
</table>

(I left out a row for brevity)

Now you can use .month to style the first column, or if you only want to style the contents and not the header cells you can use .month td.

The problem? You can only style the border, background, width and visibility. Not even the text-alignment. Why? No idea, it shouldn't be too hard to implement other styles there as well, right? (Fun fact: IE6 does support all styles this way)

nth-child()

So that leaves us with one more solution: using CSS3's pseudo-classes. The nth-child() selector allows you to choose specific siblings of elements without the need for classes. For example, if you want to style the "month" column you only have to count to one:

.sales td:nth-child(1) {
  color: red;
}

Or if you want to align both the heading and content cells that contain numbers to the right:

.sales tr :nth-child(2),
.sales tr :nth-child(3) {
  text-align: right;
}

There's a lot more to the nth-child than just this. You can use counters to select every nth element: :nth-child(2n+1) selects every second element, starting with the first, :nth-child(-n+3) styles only the first three elements, and if that's getting too confusing don't visit nthmaster.com, because I've only barely scratched the surface.

The downsides

Of course there's some minor downsides to this method. First of all, it's not supported by IE8 and lower. I know, that's still a problem, but Microsoft has been getting better at pushing their browser updates so I expect it won't even be too long before IE8 won't have to be supported anymore. Or you can just use Selectivizr.

Another downside is that it gets a little harder to maintain. When you have to add a column to a table, you'll have to re-count instead of just adding a <td> with a class. If you know your tables are going to change a lot, maybe stick to classes for now.

All in all though, for projects where I know the HTML doesn't change much and I'm not too bound by supporting older browsers, I tend to use these pseudo-selectors more and more.

If you feel like playing around a bit more with these rules, see this awesome Pseudo-class selector tester and the aforementioned nthmaster.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>