Styling Tables with Pseudoclasses

0
198

A pseudoclass in CSS is a way to select elements based on information that lies outside the document or information that can’t be expressed using normal selectors. You’ve probably used pseudoclasses like :hover before to change the color of a link when the user hovers over it with
their mouse pointer. CSS3 has several new pseudoclasses that make locating elements much easier.

Improving an Invoice

AwesomeCo uses a third-party billing and invoicing system for products it ships. You see, one of AwesomeCo’s biggest markets is conference swag, such as pens, cups, shirts, and  anything else you can slap your logo on. You’ve been asked to make the invoice more readable. Right now, the developers are producing a standard HTML table that looks like the one in Figure 4.1, on the following page.

It’s a pretty standard invoice with prices, quantities, row totals, a subtotal, a shipping total, and a grand total for the order. It would be easier to read if every other row were colored  differently. It would also be helpful if the grand total was a different color so that it stands out more.

The code for the table looks like this. Copy it into your own file so you can work with it.

<table >
<tr>
<th>Item</th>
<th>Pri ce</th>
<th>Quanti ty</th>
<th>Total</th>
</tr>
<tr>
<td>Coffee mug</td>
<td>$10.00</td>
<td>5</td>
<td>$50.00</td>
</tr>
<tr>
<td>Polo shirt</td>
<td>$20.00</td>
<td>5</td>

unstyled HTML table<td>$100.00</td>
</tr>
<tr>
<td>Red stapler</td>
<td>$9.00</td>
<td>4</td>
<td>$36.00</td>
</tr>
<tr>
<td colspan=”3″>Subtotal</td>
<td>$186.00</td>
</tr>
<tr>
<td col span=”3″>Shi ppi ng</td>
<td>$12.00</td>
</tr>
<tr>
<td colspan=”3″>Total Due</td>
<td>$198.00</td>
</tr>
</table>

First, let’s get rid of the hideous default table border.

table{
wi dth:
border
th, td{
border: none;

We’ll also style the header a bit by giving it a black background with white text.

th{
background-color: #000;
color: #fff;

Apply that style, and the table looks like this:

With the table’s borders and spacing cleaned up a bit, we can start using the pseudoclasses to style individual rows and columns. We’ll start by striping the table.

Striping Rows with :nth-of-type

Adding “zebra striping” to tables is something we’ve all seen. It’s useful because it gives users horizontal lines to follow. This kind of styling is best done in CSS, the presentation layer. That has traditionally meant adding additional class names to our table rows like “odd” and “even.”
We don’t want to pollute our table’s markup like that, because the HTML5 specification encourages us to avoid using class names that define presentation. Using some new selectors, we can get what we want without changing our markup at all, truly separating presentation
from content.

The nth-of-type selector finds every nth element of a specific type using either a formula or keywords. We’ll get into the formula in more detail soon, but first, let’s focus on the keywords, because they’re immediately easier to grasp.

We want to stripe every other row of the table with a different color, and the easiest way to do that is to find every even row of the table and give it a background color. We then do the same thing with the odd rows. CSS3 has even and odd keywords that support this exact situation.

tr:nth-of-type(even){
background-color: #F3F3F3;
}
tr:nth-of-type(odd) {
background-col or:#ddd;
}

So, this selector says, “Find me every even table row and color it. Then find every odd row and color that too.” That takes care of our zebra striping, without resorting to any scripting or extra class names on rows.

With the styles applied, our table looks like this:

Now let’s work on aligning the columns in the table.

Aligning Column Text with :nth-child

By default, all of the columns in our invoice table are left-aligned. Let’s right-align every column except for the first column. This way, our price and quantity columns will be right-aligned and easier to read. To do that, we can use nth-child, but first we have to learn how it works.

The nth-child selector looks for child elements of an element and, like nth-of-type, can use keywords or a formula.

The formula is an+b, where b is the offset, and a is a multiple. That description is not particularly helpful without some context, so let’s look at it in the context of our table.

If we wanted to select all of the table rows, we could use this selector:

table tr:nth-child(n)

We’re not using any multiple, nor are we using an offset.

However, if we wanted to select all rows of the table except for the first row, which is the row containing the column headings, we would use this selector that uses an offset:

table tr:nth-child(n+2)

If we wanted to select every other row of our table, we’d use a multiple, or 2n.

table tr:nth-child(2n)

If you wanted every third row, you’d use 3n.

You can also use the offset so that you can start further down the table. This selector would find every other row, starting with the fourth row:

table tr:nth-child(2n+4)

So, we can align every column except the first one with this rule:

td:nth-child(n+2){
text-align: right;
}

At this point, our table is really shaping up:

Now, let’s style the last row of the table.

Bolding the Last Row with :last-child

The invoice is looking pretty good right now, but one of the managers would like the bottom row of the table to be bolder than the other rows so it stands out more. We can use last-child for that too, which grabs the last child in a group.

Applying a bottom margin to paragraphs so that they are evenly spaced on a page is a common practice among many web developers. This can sometimes lead to an extra bottom margin at the end of a group, and that might be undesirable. For example, if the paragraphs are sitting inside of a sidebar or callout box, we may want to remove the bottom margin from the last paragraph so that there’s not wasted space between the bottom of the last paragraph and the border of the box. The last-child selector is the perfect tool for this. We can use it to remove the margin from the last paragraph.

p{ margin-bottom: 20px }
#sidebar p:last-child{ margin-bottom: 0; }

Let’s use this same technique to bold the contents of the last row.

tr:last-child{
font-weight: bolder;
}

Let’s do the same thing with the last column of the table. This will help the line totals stand out too.

td:last-child{
font-weight: bolder;
}

Finally, we’ll make the total’s font size bigger by using last-child with descendant selectors. We’ll find the last column of the last row and style it with this:

tr:last-child td:last-child{
font-size:24px;
}

We’re almost done, but there are a few things left to do with the last  three rows of the table.

Counting Backward with :nth-last-child

We’d like to highlight the shipping row of the table when there’s a discounted shipping rate. We’ll use nth-last-child to quickly locate that row. You saw how you can use nth-child and the formula an+b to select specific child elements in Section 7, Aligning Column Text with :nthchild,
on page 77. The nth-last-child selector works exactly the same way, except that it counts backward through the children, starting at the last child first. This makes it easy to grab the second-to-last element in a group. It turns out we need to do just that with our invoice table.

So, to find our shipping row, we’d use this code:

tr:nth-last-child (2){
color: green;
}

Here, we’re just specifying a specific child, the second to the last.

There’s one last thing we should do with this table, though. Earlier, we right-aligned all the columns except for the first column, and although that looks fine for the rows of the table with the item descriptions and prices, it makes the last three rows of the table look a little funny. Let’sright-align the bottom three rows as well. We can do that by using nthlast- child with a negative value for n and a positive value for a in our formula, like this:

tr:nth-last-child(-n+3) td{
text-align: right;
}

You can think of this as a range selector…it’s using the offset of 3, and since we’re using nth-last-child, it’s grabbing every element before the offset. If you were using nth-child, this formula would grab every row up to the offset.

Our newly styled table, shown in Figure 4.2, on the following page, looks much better now, and we didn’t have to change the underlying markup one bit. Many of the selectors we used to accomplish this are not yet available to people using Internet Explorer, so we need a workaround for them.

Falling Back

Current versions of Opera, Firefox, Safari, and Chrome all understand these selectors, but Internet Explorer versions 8.0 and older will just ignore these entirely. You’ll need a good fallback solution, and you have a choice to make.

Our styled tableChange the HTML Code

The most obvious solution that works everywhere is to modify the underlying code. You could attach classes to all the cells in the table and apply basic CSS to each class. This is the worst choice, because it mixes presentation and content and is exactly the kind of thing we’re using CSS3 to avoid. Someday we wouldn’t need all that extra markup, and it would be painful to remove it.

Use JavaScript

The j Query library already understands most of the CSS3 selectors we used, so we could quickly write a method to style the table that way, but there’s an easier way.

Keith Clark has written a great little library called IE-css32 that adds support for CSS3  selectors to Internet Explorer. All we need to do is add a couple of scripts to our page.

The IE-CSS3 library can use jQuery, Prototype, or several other libraries under the hood, but I prefer to use the DOMAssistant3 library because it has the best support for all the  pseudoclasses we’ve used here.

Download both of those libraries, and then link them to your document. Since this is for IE only, you can place them in a conditional comment so they’ll be used only by your IE users.

great in Internet Explorer.

<! — [ i f (gte IE 5.5)&(lte IE 8)]>
<script type=”text/javascript”
src=” j s/DOMAssi stantCompressed-2 .8. j s”x/scri pt>
<script type=”text/javascript”
src=” j s/i e-css3 . j s”x/scri pt>
<![endif]–>

Placing those scripts in the page makes things look just great in Internet Explorer. You can see what it looks like in Figure 4.3.

Although this will require the user to have JavaScript turned on, the table styling is mainly there to make the content easier to see. Lack of styling doesn’t prevent anyone from reading the invoice.

Styling elements is a whole lot easier with CSS3, especially if we don’t have the ability to modify the HTML we’re targeting. When you’re styling interfaces, use the semantic hierarchy and these new selectors before you add additional markup. You will find your code much  easier to maintain.