The parts of CSS3 that seem to grab the most column inches on blogs and in articles are the shiny bits. Rounded corners, text shadow and new ways to achieve CSS layouts are all exciting and bring with them all kinds of possibilities for web design. However what really gets me, as a developer, excited is a bit more mundane.
In this article I’m going to take a look at some of the ways our front and back-end code will be simplified by CSS3, by looking at the ways we achieve certain visual effects now in comparison to how we will achieve them in a glorious, CSS3-supported future. I’m also going to demonstrate how we can use these selectors now with a little help from JavaScript – which can work out very useful if you find yourself in a situation where you can’t change markup that is being output by some server-side code.
The wonder of nth-child
So why does nth-child get me so excited? Here is a really common situation, the designer would like the tables in the application to look like this:

Setting every other table row to a different colour is a common way to enhance readability of long rows. The tried and tested way to implement this is by adding a class to every other row. If you are writing the markup for your table by hand this is a bit of a nuisance, and if you stick a row in the middle you have to change the rows the class is applied to. If your markup is generated by your content management system then you need to get the server-side code to add that class – if you have access to that code.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Striping every other row - using classes</title>
<style type="text/css">
body {
padding: 40px;
margin: 0;
font: 0.9em Arial, Helvetica, sans-serif;
}
table {
border-collapse: collapse;
border: 1px solid #124412;
width: 600px;
}
th {
border: 1px solid #124412;
background-color: #334f33;
color: #fff;
padding: 0.4em;
text-align: left;
}
td {
padding: 0.4em;
}
tr.odd td {
background-color: #86B486;
}
</style>
</head>
<body>
<table>
<tr>
<th>Name</th>
<th>Cards sent</th>
<th>Cards received</th>
<th>Cards written but not sent</th>
</tr>
<tr>
<td>Ann</td>
<td>40</td>
<td>28</td>
<td>4</td>
</tr>
<tr class="odd">
<td>Joe</td>
<td>2</td>
<td>27</td>
<td>29</td>
</tr>
<tr>
<td>Paul</td>
<td>5</td>
<td>35</td>
<td>2</td>
</tr>
<tr class="odd">
<td>Louise</td>
<td>65</td>
<td>65</td>
<td>0</td>
</tr>
</table>
</body>
</html>
This situation is something I deal with on almost every project, and apart from being an extra thing to do, it just isn’t ideal having the server-side code squirt classes into the markup for purely presentational reasons. This is where the nth-child pseudo-class selector comes in. The server-side code creates a valid HTML table for the data, and the CSS then selects the odd rows with the following selector:
tr:nth-child(odd) td {
background-color: #86B486;
}
The odd and even keywords are very handy in this situation – however you can also use a multiplier here. 2n would be equivalent to the keyword ‘odd’ 3n would select every third row and so on.
Browser support
Sadly, nth-child has pretty poor browser support. It is not supported in Internet Explorer 8 and has somewhat buggy support in some other browsers. Firefox 3.5 does have support. In some situations however, you might want to consider using JavaScript to add this support to browsers that don’t have it. This can be very useful if you are dealing with a Content Management System where you have no ability to change the server-side code to add classes into the markup.
I’m going to use jQuery in these examples as it is very simple to use the same CSS selector used in the CSS to target elements with jQuery – however you could use any library or write your own function to do the same job. In the CSS I have added the original class selector to the nth-child selector:
tr:nth-child(odd) td, tr.odd td {
background-color: #86B486;
}
Then I am adding some jQuery to add a class to the markup once the document has loaded – using the very same nth-child selector that works for browsers that support it.
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(document).ready(function(){
$("tr:nth-child(odd)").addClass("odd");
});
</script>
We could just add a background colour to the element using jQuery, however I prefer not to mix that information into the JavaScript as if we change the colour on our table rows I would need to remember to change it both in the CSS and in the JavaScript.
Doing something different with the last element
So here’s another thing that we often deal with. You have a list of items all floated left with a right hand margin on each element constrained within a fixed width layout. If each element has the right margin applied the margin on the final element will cause the set to become too wide forcing that last item down to the next row as shown in the below example where I have used a grey border to indicate the fixed width.

Currently we have two ways to deal with this. We can put a negative right margin on the list, the same width as the space between the elements. This means that the extra margin on the final element fills that space and the item doesn’t drop down.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>The last item is different</title>
<style type="text/css">
body {
padding: 40px;
margin: 0;
font: 0.9em Arial, Helvetica, sans-serif;
}
div#wrapper {
width: 740px;
float: left;
border: 5px solid #ccc;
}
ul.gallery {
margin: 0 -10px 0 0;
padding: 0;
list-style: none;
}
ul.gallery li {
float: left;
width: 240px;
margin: 0 10px 10px 0;
}
</style>
</head>
<body>
<div id="wrapper">
<ul class="gallery">
<li><img src="xmas1.jpg" alt="baubles" /></li>
<li><img src="xmas2.jpg" alt="star" /></li>
<li><img src="xmas3.jpg" alt="wreath" /></li>
</ul>
</div>
</body>
</html>
The other solution will be to put a class on the final element and in the CSS remove the margin for this class.
ul.gallery li.last {
margin-right: 0;
}
This second solution may not be easy if the content is generated from server-side code that you don’t have access to change.
It could all be so different. In CSS3 we have marvellously common-sense selectors such as last-child, meaning that we can simply add rules for the last list item.
ul.gallery li:last-child {
margin-right: 0;
}
This removed the margin on the li which is the last-child of the ul with a class of gallery. No messing about sticking classes on the last item, or pushing the width of the item out wit a negative margin.
If this list of items repeated ad infinitum then you could also use nth-child for this task. Creating a rule that makes every 3rd element margin-less.
ul.gallery li:nth-child(3n) {
margin-right: 0;
}

A similar example is where the designer has added borders to the bottom of each element – but the last item does not have a border or is in some other way different. Again, only a class added to the last element will save you here if you cannot rely on using the last-child selector.
Browser support for last-child
The situation for last-child is similar to that of nth-child, in that there is no support in Internet Explorer 8. However, once again it is very simple to replicate the functionality using jQuery. Adding our .last class to the last list item.
$("ul.gallery li:last-child").addClass("last");
We could also use the nth-child selector to add the .last class to every third list item.
$("ul.gallery li:nth-child(3n)").addClass("last");
Fun with forms
Styling forms can be a bit of a trial, made difficult by the fact that any CSS applied to the input element will effect text fields, submit buttons, checkboxes and radio buttons. As developers we are left adding classes to our form fields to differentiate them. In most builds all of my text fields have a simple class of text whereas I wouldn’t dream of adding a class of para to every paragraph element in a document.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Syling form fields</title>
<style type="text/css">
body {
padding: 40px;
margin: 0;
font: 0.9em Arial, Helvetica, sans-serif;
}
form div {
clear: left;
padding: 0 0 0.8em 0;
}
form label {
float: left;
width: 120px;
}
form .text, form textarea {
border:1px solid #333;
padding: 0.2em;
width: 400px;
}
form .button {
border: 1px solid #333;
background-color: #eee;
color: #000;
padding: 0.1em;
}
</style>
</head>
<body>
<h1>Send your Christmas list to Santa</h1>
<form method="post" action="" id="christmas-list">
<div><label for="fName">Name</label>
<input type="text" name="fName" id="fName" class="text" /></div>
<div><label for="fEmail">Email address</label>
<input type="text" name="fEmail" id="fEmail" class="text" /></div>
<div><label for="fList">Your list</label>
<textarea name="fList" id="fList" rows="10" cols="30"></textarea></div>
<div><input type="submit" name="btnSubmit" id="btnSubmit" value="Submit" class="button" ></div>
</form>
</body>
</html>
Attribute selectors provide a way of targeting elements by looking at the attributes of those elements. Unlike the other examples in this article which are CSS3 selectors, the attribute selector is actually a CSS2.1 selector – it just doesn’t get much use because of lack of support in Internet Explorer 6. Using attribute selectors we can write rules for text inputs and form buttons without needing to add any classes to the markup. For example after removing the text and button classes from my text and submit button input elements I can use the following rules to target them:
form input[type="text"] {
border: 1px solid #333;
padding: 0.2em;
width: 400px;
}
form input[type="submit"]{
border: 1px solid #333;
background-color: #eee;
color: #000;
padding: 0.1em;
}
Another problem that I encounter with forms is where I am using CSS to position my labels and form elements by floating the labels. This works fine as long as I want all of my labels to be floated, however sometimes we get a set of radio buttons or a checkbox, and I don’t want the label field to be floated. As you can see in the below example the label for the checkbox is squashed up into the space used for the other labels, yet it makes more sense for the checkbox to display after the text.

I could use a class on this label element however CSS3 lets me to target the label attribute directly by looking at the value of the for attribute.
label[for="fOptIn"] {
float: none;
width: auto;
}

Being able to precisely target attributes in this way is incredibly useful, and once IE6 is no longer an issue this will really help to clean up our markup and save us from having to create all kinds of special cases when generating this markup on the server-side.
Browser support
The news for attribute selectors is actually pretty good with Internet Explorer 7+, Firefox 2+ and all other modern browsers all having support. As I have already mentioned this is a CSS2.1 selector and so we really should expect to be able to use it as we head into 2010! Internet Explorer 7 has slightly buggy support and will fail on the label example shown above however I discovered a workaround in the Sitepoint CSS reference comments. Adding the selector label[htmlFor="fOptIn"] to the correct selector will create a match for IE7.
IE6 does not support these selector but, once again, you can use jQuery to plug the holes in IE6 support. The following jQuery will add the text and button classes to your fields and also add a checks class to the label for the checkbox, which you can use to remove the float and width for this element.
$('form input[type="submit"]').addClass("button");
$('form input[type="text"]').addClass("text");
$('label[for="fOptIn"]').addClass("checks");
The selectors I’ve used in this article are easy to overlook as we do have ways to achieve these things currently. As developers – especially when we have frameworks and existing code that cope with these situations – it is easy to carry on as we always have done.
I think that the time has come to start to clean up our front and backend code and replace our reliance on classes with these more advanced selectors. With the help of a little JavaScript almost all users will still get the full effect and, where we are dealing with purely visual effects, there is definitely a case to be made for not worrying about the very small percentage of people with old browsers and no JavaScript. They will still receive a readable website, it may just be missing some of the finesse offered to the modern browsing experience.


Comments
Comments are ordered by helpfulness, as indicated by you. Help us pick out the gems and discourage asshattery by voting on notable comments.
Got something to add? You can leave a comment below.
20/12/2009
As an alternative to writing ad-hoc JavaScript to fill in the support gaps needed, there’s also Dean Edwards’ library that makes all these selectors (I think) work in IE.
http://code.google.com/p/ie7-js/
Vote Helpful or Unhelpful
20/12/2009
Awesome. Thank you!
Vote Helpful or Unhelpful
20/12/2009
I use attribute selectors in every and any form now. They are fantastic for usability / accessibility as they clearly highlight the field that the user is hovering over.
All in all CSS3 (and 2.1!) is going to mean less HTML markup for presentation which has to be a good thing.
Vote Helpful or Unhelpful
20/12/2009
Excellent article, definitely one of my favourites for this years 24 ways to impress your friends ;)
Can’t wait to start implementing some of the examples into my own site… it already feels like my life just got that little bit easier.
Thank You!
Vote Helpful or Unhelpful
20/12/2009
Rachel
thanks for such a detailed article and all your examples, brilliant :) I’ve shied away from some of your techniques in the past due to the poor browser support and my worries about relying on JS… will have to have another go now ;)
Thanks :)
Vote Helpful or Unhelpful
20/12/2009
Thanks for the insightful article! I have stumbled upon plenty of tutorials on how we can use selectors at their full power in the advent of CSS3 but I have to say that this is one of the most comprehensive one so far. What makes it so interesting is that you suggested using jQuery to cover up loopholes when it comes to dealing with old rusty browsers that fail to support such selectors.
It’s a shame that IE6 and IE7 are illiterate when it comes to interpreting with these selectors but I’m glad that many are on the move to switch to a better browser – and one more cheerful, triumphant news is that Google released Chrome Frame for IE which will liberate many users locked down by corporate policies and nasty tech department folks that were forced to use IE6 (e.g. due to proprietary software used by the company and etc).
Although I wouldn’t recommend using javascript to fix CSS issues due to the inherent problem that some (very few) users have javascript turned off for safety reasons, I have good faith that it still works for majority of those who are using older browsers. jQuery is a very valuable resource when it comes to dealing with CSS selectors :) thank goodness for that!
Vote Helpful or Unhelpful
20/12/2009
A caveat: Internet Explorer 8 chokes on any CSS that includes a selector it doesn’t recognize, so it doesn’t respect this line of CSS from the “nth-child last-child” example:
ul.gallery li:nth-child(3n), ul.gallery li.last { margin-right: 0; }
To get IE8 to play nicely, you’ll need to change it to this:
ul.gallery li:nth-child(3n) { margin-right: 0; }
ul.gallery li.last { margin-right: 0; }
Vote Helpful or Unhelpful
20/12/2009
jQuery also has :even and :odd filters:
$(‘tr:odd’).addClass(‘odd’);
Vote Helpful or Unhelpful
20/12/2009
Nice article. The lack of support for these brilliant selectors managed to bug me during about every project I have worked on.
Luckily with my current project I only have to care about Webkit, which by itself makes it a great project to work on :P, but with the next I may make good use of jQuery and be rid of one more source of annoyance. :) It still depends on the intended audience though, because using javascript can come with its own annoyances, as Prisca and Teddy mentioned.
@Mike Breen:
Good point. Although I think Rachel intentionally went for :nth-child() as jQuery filter, because it also accepts equations, like ‘3n’, instead of just ‘odd’ and ‘even’.
Vote Helpful or Unhelpful
21/12/2009
How about instead of using last-child do things on the other side of your objects (margin-left/border-left etc) and use the more widely accepted first-child?
Vote Helpful or Unhelpful
21/12/2009
Another approach to propping up selector support in legacy browsers is the SuperSelectors plugin I wrote a while back. It uses jQuery’s excellent CSS selector functionality to add support for a wide range of selectors, in any browser that’ll run jQuery. Classnames are totally customizable, and as of a week or so ago, it’ll even create the necessary CSS for you – so your stylesheets can be as pristine as your markup.
Source is at http://github.com/chrispatterson/jquery-super-selectors – suggestions & patches are always welcome.
Vote Helpful or Unhelpful
21/12/2009
Under the “Doing something something different with the last element” subheading, you write:
“If each element has the right margin applied the margin on the final element will cause the set to become too wide forcing that last item down to the next row as shown in the below example…”
However, the image below does not show the last element dropping to the next row, but it shows the result of applying a fix (e.g. putting a negative margin on the list).
Shouldn’t the image show the last element dropping to the next row?
Vote Helpful or Unhelpful
21/12/2009
Cool overview. CSS3 selectors rock… I use them all the time, specially in JS development. Just make sure you test that your library fully supports them cross-browser.
I would definitely just add that you can use both :nth-child and :nth-last-child to achieve restrictions depending on the number of sibling elements.
Have a look at:
http://andr3.net/blog/post/142
Vote Helpful or Unhelpful
21/12/2009
Really worth reading… nice post, Bookmarked! Thanks…
-Deepu
Vote Helpful or Unhelpful
21/12/2009
That’s excellent. I’ve been using the nth-Element in a 4 by 4 Thumbnail-Gallery and really needed to address the last Thumb in each row to remove the right-Margin (Just the Problem you described). No Problem with n-th-Element in FF and Safari. But I was stumped on how to make this work in IE without having to add a class to each of these Elements in the markup.
With your jQuery Solution (which I didn’t thought of) you just made my day. :-) Thanks
Vote Helpful or Unhelpful
23/12/2009
That’s exactly what I do. I use Dean Edwards’ IE7.js as mentioned by Paul D. Waite which brings support for :first-child to IE6 as well and then add all margins, padding and borders on the left of elements.
Using IE7.js you can also take advantage of the CSS2.1 selectors you talk about in your form example for IE6. The one area where I’ve had trouble has been targetting particular labels but I’m going to try out the htmlfor trick and see how it goes.
Vote Helpful or Unhelpful
23/12/2009
I think if you are doing a lot of this then Dean Edward’s IE7.js is a good idea. Personally I tend to use JavaScript solutions for small enhancements on sites that already use jQuery for other things so it makes sense to me to just add in those selectors on a case by case basis rather than load in a bunch of stuff I am not going to need.
I’d also suggest caution if developing with a library like IE7.js in place as it is very easy to then forget about the view of the site for users of IE6 with no JavaScript. Make sure you test with the library removed to make sure nothing breaks horribly.
Vote Helpful or Unhelpful
24/12/2009
I’d like to “second” the urge of caution when developing with libraries such as IE7, not so much because of the IE6/noJS incompatibility, but because of what the crutch does to you.
For the majority of sites, the most crucial of elements (navigation, calls to action, etc.) should not require extra logic (Javascript) to function. Enhancement, of course, is perfectly acceptable.
There was an article in recent news of how Yahoo! Sports had a syntax error in the minified Javascript served to users. Many sites would simply stop functioning or lose significant features. Yahoo! Sports continued working just fine, thanks to what many call Progressive Enhancement.
As for using IE7 for fixing box-model issues with IE6, many CSS frameworks that support grid-based layouts (BlueprintCSS) take care of this already.
Vote Helpful or Unhelpful
26/12/2009
I’m also very excited about pseudo selectors. They have proven to be very powerful in the jQuery that I’ve used on my site so far. I’ve not yet used them in any CSS as I’m waiting for more widespread browser support.
Vote Helpful or Unhelpful
04/01/2010
While it’s a nice example of using CSS3 selectors may I point out a more backward compatible way of achieving the three wide grid using only CSS2, for those that need it?
Instead of margin-right on the li elements, use margin-left, and then use a negative margin left on the ul to pull it into line, e.g.,
ul { margin-left : -10px; }
li { margin-left : 10px; }
This allows you to create a grid with sides flush, but without requiring advanced selectors.
Here’s a live example: http://mattwilcox.net/sandbox/edge-to-edge/edge-to-edge-alignment.html
Vote Helpful or Unhelpful
12/01/2010
@Matt Wilcox : thank a lot for the tip, you rock !
You just help me to solve kind of problem I have on almost my websites.
Vote Helpful or Unhelpful
19/02/2010
Very useful article – particularly the details of the use of the nth-child. It is very frustrating having to add a class to every other row of a table hence the nth-child looks great. It also looks pretty useful for handling images. Is browser support any better yet?
Vote Helpful or Unhelpful
12/03/2010
I fought so long to find a solution for last-child in IE8. Thank you for your JQuery-tip.
Vote Helpful or Unhelpful
Impress us