Menu Search
Jump to the content X X
SmashingConf London Avatar

We use ad-blockers as well, you know. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. our upcoming SmashingConf London, dedicated to all things web performance.

How To Use CSS3 Pseudo-Classes

CSS3 is a wonderful thing, but it’s easy to be bamboozled by the transforms and animations (many of which are vendor-specific) and forget about the nuts-and-bolts selectors that have also been added to the specification. A number of powerful new pseudo-selectors (16 are listed in the latest W3C spec1) enable us to select elements based on a range of new criteria.

CSS3 Pseudo-Classes2

Before we look at these new CSS3 pseudo-classes, let’s briefly delve into the dusty past of the Web and chart the journey of these often misunderstood selectors.

A Brief History Of Pseudo-Classes Link

When the CSS13 spec was completed back in 1996, a few pseudo-selectors were included, many of which you probably use almost every day. For example:

  • :link
  • :visited
  • :hover
  • :active

Each of these states can be applied to an element, usually <a>, after which comes the name of the pseudo-class. It’s amazing to think that these pseudo-classes arrived on the scene before HTML44 was published by the W3C a year later in December 1997.

Further Reading on SmashingMag: Link

CSS2 Arrives Link

Hot on the heels of CSS1 was CSS29, whose recommended spec was published just two years later in May 1998. Along with exciting things like positioning were new pseudo-classes: :first-child and :lang().

There are a couple of ways to indicate the language of a document, and if you’re using HTML510, it’ll likely be by putting <html lang="en"> just after the doc type (specifying your local language, of course). You can now use :lang(en) to style elements on a page, which is useful when the language changes dynamically.

You may have already used :first-child in your documents. It is often used to add or remove a top border on the first element in a list. Strange, then, that it wasn’t accompanied by :last-child; we had to wait until CSS3 was proposed before it could meet its brother.

Why Use Pseudo-Classes? Link

What makes pseudo-classes so useful is that they allow you to style content dynamically. In the <a> example above, we are able to describe how links are styled when the user interacts with them. As we’ll see, the new pseudo-classes allow us to dynamically style content based on its position in the document or its state.

Sixteen new pseudo-classes have been introduced as part of the W3C’s CSS Proposed Recommendation11, and they are broken down into four groups: structural pseudo-classes, pseudo-classes for the states of UI elements, a target pseudo-class and a negation pseudo-class.

The W3C is the home of CSS.

Let’s now run through the 16 new pseudo-selectors one at a time and see how each is used. I’ll use the same notation for naming classes that the W3C uses, where E is the element, n is a number and s is a selector.

Sample Code Link

For many of these new selectors, I’ll also refer to some sample code so that you can see what effect the CSS has. We’ll take a regular form and make it suitable for an iPhone using our new CSS3 pseudo-classes.

Note that we could arguably use ID and class selectors for much of this form, but it’s a great opportunity to take our new pseudo-classes out for a spin and demonstrate how you might use them in a real-world example. Here’s the HTML (which you can see in action on my website):

 <h1>Awesome Widgets</h1>
 <h2>All the cool kids have got one :)</h2>
 <fieldset id="email">
 <legend>Where do we send your receipt?</legend>
 <label for="email">Email Address</label>
 <input type="email" name="email" placeholder="Email Address" />

 <fieldset id="details">
 <legend>Personal Details</legend>
 <select name="title" id="field_title">
  <option value="" selected="selected">Title</option>
  <option value="Mr">Mr</option>
  <option value="Mrs">Mrs</option>
  <option value="Miss">Miss</option>

 <label for="firstname">First Name</label>
 <input name="firstname" placeholder="First Name" />

 <label for="initial">Initial</label>
 <input name="initial" placeholder="Initial" size="3" />

 <label for="surname">Surname</label>
 <input name="surname" placeholder="Surname" />

 <fieldset id="payment">
 <legend>Payment Details</legend>

 <label for="cardname">Name on card</label>
 <input name="cardname" placeholder="Name on card" />

 <label for"cardnumber">Card number</label>
 <input name="cardnumber" placeholder="Card number" />

 <select name="cardType" id="field_cardType">
  <option value="" selected="selected">Select Card Type</option>
  <option value="1">Visa</option>
  <option value="2">American Express</option>
  <option value="3">MasterCard</option>

 <label for="cardExpiryMonth">Expiry Date</label>
 <select id="field_cardExpiryMonth" name="cardExpiryMonth">
  <option selected="selected" value="mm">MM</option>
   <option value="01">01</option>
   <option value="02">02</option>
   <option value="03">03</option>
   <option value="04">04</option>
   <option value="05">05</option>
   <option value="06">06</option>
   <option value="07">07</option>
   <option value="08">08</option>
   <option value="09">09</option>
   <option value="10">10</option>
   <option value="11">11</option>
   <option value="12">12</option>
 </select> /
 <select id="field_cardExpiryYear" name="cardExpiryYear">
   <option value="yyyy">YYYY</option>
    <option value="2011">11</option>
    <option value="2012">12</option>
    <option value="2013">13</option>
    <option value="2014">14</option>
    <option value="2015">15</option>
    <option value="2016">16</option>
    <option value="2017">17</option>
    <option value="2018">18</option>
    <option value="2019">19</option>

 <label for"securitycode">Security code</label>
 <input name="securitycode" type="number" placeholder="Security code" size="3" />

 <p>Would you like Insurance?</p>
 <input type="radio" name="Insurance" id="insuranceYes" />
  <label for="insuranceYes">Yes Please!</label>
 <input type="radio" name="Insurance" id="insuranceNo" />
  <label for="insuranceNo">No thanks</label>


 <fieldset id="submit">
 <button type="submit" name="Submit" disabled>Here I come!</button>

Our form, before and after.

1. Structural Pseudo-Classes Link

According to the W3C, structural pseudo-classes do the following:

… permit selection based on extra information that lies in the document tree but cannot be represented by other simple selectors or combinators.

What this means is that we have selectors that have been turbo-charged to dynamically select content based on its position in the document. So let’s start at the beginning of the document, with :root.

Level 3 selectors on the W3C website.

E:root Link

The :root pseudo-class selects the root element on the page. Ninety-nine times out of a hundred, this will be the <html> element. For example:

:root { background-color: #fcfcfc; }

It’s worth noting that you could style the <html> element instead, which is perhaps a little more descriptive:

html { background-color: #fcfcfc; }

iPhone Form Example
Let’s move over to our sample code and give the document some basic text and background styles:

:root {
color: #fff;
text-shadow: 0 -1px 0 rgba(0,0,0,0.8);
background: url(…/images/background.png) no-repeat #282826; }

E:nth-child(n) Link

The :nth-child() selector might require a bit of experimentation to fully understand. The easiest implementation is to use the keywords odd or even, which are useful when displaying data that consists of rows or columns. For example, we could use the following:

ul li:nth-child(odd) {
background-color: #666;
color: #fff; }

This would highlight every other row in an unordered list. You might find this technique extremely handy when using tables. For example:

table tr:nth-child(even) { … }

The :nth-child selector can be much more specific and flexible, though. You could select only the third element from a list, like so:

li:nth-child(3) { … }

Note that n does not start at zero, as it might in an array. The first element is :nth-child(1), the second is :nth-child(2) and so on.

We can also use some simple algebra to make things even more exciting. Consider the following:

li:nth-child(2n) { … }

Whenever we use n in this way, it stands for all positive integers (until the document runs out of elements to select!). In this instance, it would select the following list items:

  • Nothing (2 × 0)
  • 2nd element (2 × 1)
  • 4th element (2 × 2)
  • 6th element (2 × 3)
  • 8th element (2 × 4)
  • etc.

This actually gives us the same thing as nth-child(even). So, let’s mix things up a bit:

li:nth-child(5n) { … }

This gives us:

  • Nothing (5 × 0)
  • 5th element (5 × 1)
  • 10th element (5 × 2)
  • 15th element (5 × 3)
  • 20th element (5 × 4)
  • etc.

Perhaps this would be useful for long lists or tables, perhaps not. We can also add and subtract numbers in this equation:

li:nth-child(4n + 1) { … }

This gives us:

  • 1st element ((4 × 0) + 1)
  • 5th element ((4 × 1) + 1)
  • 9th element ((4 × 2) + 1)
  • 13th element ((4 × 3) + 1)
  • 17th element ((4 × 4) + 1)
  • etc.

SitePoint points out15 an interesting quirk here. If you set n as negative, you’ll be able to select the first x number of items like so:

li:nth-child(-n + x) { … }

Let’s say you want to select the first five items in a list. Here’s the CSS:

li:nth-child(-n + 5) { … }

This gives us:

  • 5th element (-0 + 5)
  • 4th element (-1 + 5)
  • 3rd element (-2 + 5)
  • 2nd element (-3 + 5)
  • 1st element (-4 + 5)
  • Nothing (-5 + 5)
  • Nothing (-6 + 5)
  • etc.

If you’re listing data in order of popularity, then highlighting, say, the top 10 entries might be useful.

WebDesign & Such16 has created a demo of zebra striping17, which is a perfect example of how you might use nth-child in practice.

Zebra striping a table with CSS3.

If none of your tables need styling, then you could do what Webvisionary Awards19 has done and use :nth-child to style alternating sections of its website. Here’s the CSS:

section > section:nth-child(even) {
url("../images/hr-damaged2.png") 0 bottom no-repeat;

The effect is subtle on the website, but it adds a layer of detail that would be missed in older browsers.

The :nth-child selectors in action on Webvisionary Awards.

iPhone Form Example
We could use :nth-child in a few places in our iPhone form example, but let’s focus on one. We want to hide the labels for the first three fieldsets from view and use the placeholder text instead. Here’s the CSS:

form:nth-child(-n+3) label { display: none; }

Here, we’re looking for the first three children of the <form> element (which are all fieldsets in our code) and then selecting the label. We then hide these labels with display: none;.

E:nth-last-child(n) Link

Not content with confusing us all with the :nth-child() pseudo-class, the clever folks over at the W3C have also given us :nth-last-child(n). It operates much like :nth-child() except in reverse, counting from the last item in the selection.

li:nth-last-child(1) { … }

The above will select the last element in a list, whereas the following will select the penultimate element:

li:nth-last-child(2) { … }

Of course, you could create other rules, like this one:

li:nth-last-child(2n+1) { … }

But you would more likely want to use the following to select the last five elements of a list (based on the logic discussed above):

li:nth-last-child(-n+5) { … }

If this still doesn’t make much sense, Lea Verou21 has created a useful CSS3 structural pseudo-class selector tester22, which is definitely worth checking out.

CSS3 structural pseudo-class selector tester.

iPhone Form Example
We can use :nth-last-child in our example to add rounded corners to our input for the “Card number.” Here’s our CSS, which is overly specific but gives you an idea of how we can chain pseudo-selectors together:

fieldset:nth-last-child(2) input:nth-last-of-type(3) {
border-radius: 10px; }

We first grab the penultimate fieldset and select the input that is third from last (in this case, our “Card number” input). We then add a border-radius.

:nth-of-type(n) Link

Now we’ll get even more specific and apply styles only to particular types of element. For example, let’s say you wanted to style the first paragraph in an article with a larger font. Here’s the CSS:

article p:nth-of-type(1) { font-size: 1.5em; }

Perhaps you want to align every other image in an article to the right, and the others to the left. We can use keywords to control this:

article img:nth-of-type(odd) { float: right; }
article img:nth-of-type(even) { float: left; }

As with :nth-child() and :nth-last-child(), you can use algebraic expressions:

article p:nth-of-type(2n+2) { … }
article p:nth-of-type(-n+1) { … }

It’s worth remembering that if you need to get this specific about targeting elements, then using descriptive class names instead might be more useful.

Simon Foster has created a beautiful infographic about his 45 RPM record collection24, and he uses :nth-of-type to style some of the data. Here’s a snippet from the CSS, which assigns a different background to each genre type:

ul#genre li:nth-of-type(1) {
ul#genre li:nth-of-type(2) {
ul#genre li:nth-of-type(3) {

And here’s what it looks like on his website:

The :nth-of-type selectors on “For the Record.”

iPhone Form Example
Let’s say we want every second input element to have rounded corners on the bottom. We can achieve this with CSS:

input:nth-of-type(even) {
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px; }

In our example, we want to apply this only to the fieldset for payment, because the fieldset for personal details has three text inputs. We’ll also get a bit tricky and make sure that we don’t select any of the radio inputs. Here’s the final CSS:

#payment input:nth-of-type(even):not([type=radio]) {
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
border-bottom: 1px solid #999;
margin-bottom: 10px; }

We’ll explain :not later in this article.

:nth-last-of-type(n) Link

Hopefully, by now you see where this is going: :nth-last-of-type() starts at the end of the selected elements and works backwards.

To select the last paragraph in an article, you would use this:

article p:nth-last-of-type(1) { … }

You might want to choose this selector instead of :last-child if your articles don’t always end with paragraphs.

:first-of-type and :last-of-type Link

If :nth-of-type() and :nth-last-of-type() are too specific for your purposes, then you could use a couple of simplified selectors. For example, instead of this…

article p:nth-of-type(1) {
font-size: 1.5em; }

… we could just use this:

article p:first-of-type {
font-size: 1.5em; }

As you’d expect, :last-of-type works in exactly the same way but from the last element selected.

iPhone Form Example
We can use both :first-of-type and :last-of-type in our iPhone example, particularly when styling the rounded corners. Here’s the CSS:

fieldset input:first-of-type:not([type=radio]) {
border-top-left-radius: 10px;
border-top-right-radius: 10px; }

fieldset input:last-of-type:not([type=radio]) {
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px; }

The first line of CSS adds a top rounded border to all :first-of-type inputs in a fieldset that aren’t radio buttons. The second line adds the bottom rounded border to the last input element in a fieldset.

:only-of-type Link

There’s one more type selector to look at: :only-of-type(). This is useful for selecting elements that are the only one of their kind in their parent element.

For example, consider the difference between this CSS selector…

p {
font-size: 18px; }

… and this one:

p:only-of-type {
font-size: 18px; }

The first selector will style every paragraph element on the page. The second element will grab a paragraph that is the only paragraph in its parent.

This could be handy when you are styling content or data that has been dynamically outputted from a database and the query returns only one result.

Devsnippet has created a demo in which single images are styled differently from multiple images.

Devsnippet’s demo for :only-of-type.

iPhone Form Example
In the case of our iPhone example, we can make sure that all inputs that are the only children of a fieldset have rounded corners on both the top and bottom. The CSS would be:

fieldset input:only-of-type {
border-radius: 10px; }

:last-child Link

It’s a little strange that :first-child was part of the CSS2 spec but that its partner in crime, :last-child, didn’t appear until CSS3. It takes no expressions or keywords here; it simply selects the last child of its parent element. For example:

li {
border-bottom: 1px solid #ccc; }

li:last-child {
border-bottom: none; }

This is a useful way to remove bottom borders from lists. You’ll see this technique quite often in WordPress widgets.

Rachel Andrew looks at :last-child and other CSS pseudo-selectors in her 24 Ways article “Cleaner Code With CSS3 Selectors27.” Rachel shows us how to use this selector to create a well-formatted image gallery without additional classes.

:last-child CSS in action from Rachel Andrew28
The CSS for :last-child in action, courtesy of Rachel Andrew.

:only-child Link

If an element is the only child of its parent, then you can select it with :only-child. Unlike with :only-of-type, it doesn’t matter what type of element it is. For example:

li:only-child { … }

We could use this to select list elements that are the only list elements in their <ol> or <ul> parent.

:empty Link

Finally, in structural pseudo-classes, we have :empty. Not surprisingly, this selects only elements that have no children and no content. Again, this might be useful when dealing with dynamic content outputted from a database.

#results:empty {
background-color: #fcc; }

You might use the above to draw the user’s attention to an empty search results section.

2. The Target Pseudo-Class Link

:target Link

This is one of my favourite pseudo-classes, because it allows us to style elements on the page based on the URL. If the URL has an identifier (that follows an #), then the :target pseudo-class will style the element that shares the ID with the identifier. Take a URL that looks like this:

The section with the id summary can now be styled like so:

:target {
background-color: #fcc; }

This is a great way to style elements on pages that have been linked to from external content. You could also use it with internal anchors to highlight content that users have skipped to.

Perhaps the most impressive use of :target I’ve seen is Corey Mwamba’s Scrolling Site of Green29. Corey uses some creative CSS3 and the :target pseudo-class to create animated tabbed navigation30. The demo contains some clever use of CSS3, illustrating how pseudo-classes are often best used in combination with other CSS selectors.

Corey’s Scrolling Site of Green.

There’s also an interesting example over at Web Designer Notebook32. In it, :target and Webkit animations are used to highlight blocks of text in target divs. Chris Coyier also creates a :target-based tabbing system at CSS-Tricks33.

iPhone Form Example
As you’ll see on my demo page, I’ve added a navigation bar at the top that skips down to different sections of the form. We can highlight any section the user jumps to with the following CSS:

:target {
background-color: rgba(255,255,255,0.3);


3. The UI Element States Pseudo-Classes Link

:enabled and :disabled Link

Together with :checked, :enabled and :disabled make up the three pseudo-classes for UI element states. That is, they allow you to style elements (usually form elements) based on their state. A state could be set by the user (as with :checked) or by the developer (as with :enabled and :disabled). For example, we could use the following:

input:enabled {
background-color: #dfd; }

input:disabled {
background-color: #fdd; }

This is a great way to give feedback on what users can and cannot fill in. You’ll often see this dynamic feature enhanced with JavaScript.

iPhone Form Example
To illustrate :disabled in practice, I have disabled the form’s “Submit” button in the HTML and added this line of CSS:

:disabled {
color: #600; }

The button text is now red!

:checked Link

The third pseudo-class here is :checked, which deals with the state of an element such as a checkbox or radio button. Again, this is very useful for giving feedback on what users have selected. For example:

input[type=radio]:checked {
font-weight: bold; }

iPhone Form Example
As a flourish, we can use CSS to highlight the text next to each radio button once the button has been pressed:

input:checked + label {
text-shadow: 0 0 6px #fff; }

We first select any input that has been checked, and then we look for the very next <span> element that contains our text. Highlighting the text with a simple text-shadow is an effective way to provide user feedback.

4. Negation Pseudo-Class Link

:not Link

This is another of my favorites, because it selects everything except the element you specify. For example:

:not(footer) { … }

This selects everything on the page that is not a footer element. When used with form inputs, they allow us to get a little sneakier:

input:not([type=submit]) { … }
input:not(disabled) { … }

The first line selects every form input that’s not a “Submit” button, which is useful for styling forms. The second selects all input elements that are not enabled; again useful for giving feedback on how to fill in a form.

iPhone User Example
You’ve already seen the :not selector in action. It’s particularly powerful when chained with other CSS3 pseudo-selectors. Let’s take a closer look at one example:

fieldset input:not([type=radio]) {
margin: 0;
width: 290px;
font-size: 18px;
border-radius: 0;
border-bottom: 0;
border-color: #999;
padding: 8px 10px;}

Here we are selecting all inputs inside fieldset elements that are not radio buttons. This is incredibly useful when styling forms because you will often want to style text inputs different from select boxes, radio buttons and “Submit” buttons.

Check out our final page.

What’s Old Is New Again Link

Let’s go back to the beginning of our story and the humble a:link. HTML5 arrived on the scene recently and brought with it an exciting change34 to the <a> element that gives the CSS3 pseudo-selector an additive effect.

An <a> element can now be wrapped around block-level elements, turning whole sections of your page into links (as long as those sections don’t contain other interactive elements). Whereas JavaScript was once popular for making entire <div> elements clickable, you can now do so by wrapping sections in <a> tags, like so:

<a href="">
<div id="advert">
<h1>Jackson’s Widgets</h1>
<h2>The finest widgets in Kentucky</h2>
<p>Buy Jackson’s Widgets today,
and be sure of a trouble-free life for you,
your widget and your machinery.
Trusted and sold since 1896.</p>

The implication for CSS pseudo-selectors is that you can now style a <div> based on whether it is being hovered over (a:hover) or is active (a:active), like so:

a:hover #advert {
background-color: #f7f7f7; }

Anything that decreases JavaScript and increases semantic code has to be good!

Cross-Browser Compatibility Link

You had to ask, didn’t you! Unbelievably, Internet Explorer 8 (and earlier) doesn’t support any of these selectors, whereas the latest versions of Chrome, Opera, Safari and Firefox all do. Before your blood boils, consider the following solutions.

Internet Explorer 9 Link

Unless you’ve been living under a rock for the last week, you’ll have heard that Microsoft unleashed its latest browser on an unsuspecting public. The good thing is, it’s actually quite good. While I don’t expect people who are reading this article to change their browsing habits, it’s worth remembering that the majority of the world uses IE; and thanks to Windows Update and a global marketing campaign, we can hope to see IE9 as the dominant Windows browser in the near future. That’s good for Web designers, and it’s good for pseudo-selectors. But what about IE8 and its ancestors?

Internet Explorer 9 is here.

JavaScript Link

Our old friend JavaScript comes to the rescue. I particularly like Selectivizr36 by Keith Clark. Keith has put together a lovely script that, in combination with your JavaScript library of choice, adds CSS3 pseudo-class selector functionality for earlier versions of IE. Be warned that some libraries fare better than others: if you’re using MooTools with Selectivizr, then all the pseudo-classes will be available, but if you’re relying on jQuery to do the heavy lifting, then a number of the selectors won’t work at all.


Keith recently released a jQuery plug-in38 that extends jQuery to include support for the following CSS3 pseudo-class selectors:

  • :first-of-type
  • :last-of-type
  • :only-of-type
  • :nth-of-type
  • :nth-last-of-type

It’s also worth looking at the ubiquitous ie7.js script (and its successors) by Dean Edwards39. This script solves a number of IE-related problems, including CSS3 pseudo-selectors.

So, Should We Start Using CSS3 Pseudo-Selectors Today? Link

I guess the answer to that question depends on how you view JavaScript. It’s true that pseudo-selectors can be completely replaced with classes and IDs; but it’s also true that, when styling complex layouts, pseudo-selectors are both incredibly useful and the natural next step for your CSS. If you find that they improve the readability of your CSS and reduce the need for (non-semantic) classes in your HTML, then it I’d definitely recommend embracing them today.

You could use two selectors and fall back on a class name, but that would just duplicate work. It also means that you wouldn’t need the pseudo-classes in the first place. But if you did choose to go down this path, the code might look something like this:

li.third { … }

This method is not as flexible as using pseudo-classes because you have to keep updating the HTML and CSS when the page content changes.

If a lot of your users don’t have JavaScript enabled, that puts you in a bit of a bind. Many Web designers argue that functionality (i.e. JavaScript) is different from layout (i.e. CSS), and so you should not rely on JavaScript to make pseudo-selectors work in IE8 and earlier.

While I agree with the principle, in practice I believe that providing the best possible experience to 99% of your users is better than accounting for the remaining 1% (or however big your non-JavaScript base may be).

Follow your website’s analytics, and be prepared to make decisions that improve your skills as a Web designer and, more importantly, provide the best experience possible to the majority of users.

Final Thoughts Link

It’s hard not to be depressed by IE8’s complete lack of support for pseudo-classes. Arguably, having the browser calculate and recalculate page styles in this fashion will have implications for rendering speed; but because all other major browsers now support these selectors, it’s frustrating that most of our users can’t benefit from them without a JavaScript hack.

But as Professor Farnsworth says, “Good news everyone!” Breaking on the horizon is the dawn of Internet Explorer 9, and Microsoft has made sure that its new browser supports each and every one40 of the selectors discussed in this article.

CSS3 pseudo-selectors won’t likely take up large chunks of your style sheets. They are specific yet dynamic and are more likely, at least initially, to add finishing touches to a page than to set an overall style. Perhaps you want to drop the bottom border in the last item of a list, or give visual feedback to users as they fill in a form. This is all possible with CSS3, and as usage becomes more mainstream, I expect these will become a regular part of the Web designer’s toolbox.

If you’ve seen any interesting or exciting uses of these selectors out there in the field, do let us know in the comments below.

Other Resources Link

You may be interested in the following articles and related resources:

(al) (ik)

Footnotes Link

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44

↑ Back to top Tweet itShare on Facebook

Richard (@richardshepherd) is a UK based web designer and front-end developer. He loves to play with HTML5, CSS3, jQuery and WordPress, and currently works full-time bringing to life. He has an awesomeness factor of 8, and you can also find him at

  1. 1

    Great article, knew most of this already but its a great list with good examples.

  2. 2

    Why MS don’t push IE9 on Windows XP? Why?? :-(

  3. 3

    Michael Ward

    March 30, 2011 4:08 am

    The :last-child pseduo-selector was originally omitted from css2 because of performance considerations. It’s easy for a browser to know if an element is the first child as soon as it comes across it – there’s little to no performance penalty – but the browser has to loop back on itself when it gets to the last child. This will probably change the formatting of the element and force a full reflow of the doucment. That’s expensive CPU wise.

    Of course, this seems a little silly now – but back when css 2 was being drafted these performance considerations were very real. Even today, we should be careful about the use of dynamic selectors if we care about performance.

  4. 4

    One of the best articles I’ve read! I’ll keep it as a quick reference guide for my projects from now on. Tks for share!

  5. 5

    Great example for Pseudo class really awesome.

  6. 6

    ’cause mainstream support for XP was ended a year ago.

  7. 7

    John Flickinger

    March 30, 2011 5:19 am

    Another possible reason is that IE9 uses hardware acceleration for rendering which probably hooks into the OS. Versions of Vista before SP2 don’t support IE9 either.

  8. 8

    John Flickinger

    March 30, 2011 5:20 am

    With the background color example, what is the difference between targeting the body tag and targeting the html tag?

  9. 9

    Richard Shepherd

    March 30, 2011 5:20 am

    Hey Michael,

    You make a really good point about speed. Lots of pseudo-selectors can affect performance, although I’ve yet to see a page that has suffered a great deal from this.


  10. 10

    great article. annoying links on either side of the page though, thanks for that…

  11. 11

    Linus Hultin

    March 30, 2011 5:47 am

    Wow! Simply great article. Just what I needed. Just one question(maybe I’ve missed it in the article); what if I have a class where I want the first letter of each word to be a bigger font, is this possible?

  12. 12

    You’re looking for this:

    .yourClass {
    text-transform: capitalize;

    edit ( sorry, misread that… thought you said cap… not enlarge font… nothing comes to mind.)

  13. 13

    Outstanding article! I am intrigued by the :not, :empty and :target pseudo-classes. I can see many of these being extremely helpful. You outlined each new pseudo-class perfectly and explained them with great examples. #smftw

  14. 14

    Zach Hilbrich

    March 30, 2011 8:46 am

    This was an amazing article im a new to all this CSS/Javascript/HTML, but man it is exciting to learn about. I hope i can apply this to some of the stuff im trying to put together myself.

  15. 15

    Craig Anthony

    March 30, 2011 10:22 am

    Nice write-up. Thanks.

    To add to this article, here is another. It specifies browser compatibility per selector. Using “nth” is still a bit tricky since it isn’t supported in IE8. Sure there are fixes, but they aren’t that super in my humble opinion.

    The 30 CSS Selectors you Must Memorize:

  16. 16

    Thanks for this quite exhaustive article. Very useful.

    About IE > radical solution : stop fixing it > Users will change their browser > end of headache…[half-troll inside]

  17. 17

    What about the :before and :after pseudo classes ??…
    Why u left out on these?
    These are very tricky and important… I want to know more about them..!

  18. 18

    Very nice tutorial really learnt from it. Pseudo classes can make the life of web designer much easier. :- )

  19. 19

    Richard Shepherd

    March 30, 2011 11:31 pm

    Hey Linus,

    Yep! You need :first-letter pseudo element, which you can read about over at


  20. 20

    :first-letter is a css2 pseudo-class you could use.
    Should work even on older versions of Internet Explorer.

    .yourClass:first-letter {
    font-size: 1.5em

  21. 21

    Great post, simple and usefull :D

  22. 22

    I’d also like to know this.

  23. 23

    i’ve a question..
    can i combine two pseudo class.
    like :first-child and :hover in selector?

  24. 24

    Thanks for sharing this post.I like this post.It contains good examples of how to use css3 pseudo classes.

  25. 25

    There’s no difference it just depends how you use them. In my code I usually style both the html and body tags as it means I need less divs in my HTML for containers/backgrounds.

  26. 26

    Richard Shepherd

    March 31, 2011 5:02 am

    Hey Rajiv,

    You’re right, :before and :after are both important and useful! However, in this article I’ve focused on CSS3 pseudo-classes, and :before and :after are pseudo-elements from the CSS2 spec.

    You can read more about them over at

    Hope that helps!

  27. 27

    Richard Shepherd

    March 31, 2011 5:09 am

    Hi Rian,

    Absolutely! It’s one of the great things about pseudo-classes :)

    For example, you could try

    section:nth-of-type(-n+3) ul:first-child li:hover { … }


  28. 28

    Michel Bozgounov

    March 31, 2011 5:24 am

    Excellent article! :)

    On a //sidenote, I think CSS(3) starts to become a bit too complex to my taste… It now looks more like a programming language (nth-child minus three multiplied by two will target the seventh row from a table, counting from the top?… :-)… closer to JavaScript, for example. And now we can also do animations with it, paint gradients, round corners, rotate/scale/move/fade-in/fade-out objects, etc…

    While CSS2.1 was (in some ways) a bit limited, it was fairly simple and all you had to do was take into account the difference in browsers and how they interpret the standard. Now it seems large parts of JavaScript are moving into CSS3, and make me feel like I am starting to become a Web programmer (and not front end developer). Maybe change is a good thing, though… time will show! :)

  29. 29

    My major gripe with a lot of this CSS3 stuff is if we’re STILL dealing with IE6 (so much to the point where Microsoft itself is running a website to celebrate the Death of IE6) how long are we going to be stuck with IE7 and IE8. I purposely fire up IE8 whenever I see an HTML5/CSS3 demo just so I can ground myself and know that I can’t use any of these techniques.

  30. 30

    Great article
    I particularly wanted to see live demos but overall it was an excellent writing.
    Thank you

  31. 31

    An even more radical solution – write cleaner code > don’t present broken sites to users > enjoy the challenge > get paid from clients.

  32. 32

    Sebastian Green

    March 31, 2011 7:07 am

    Great artical. Read up on all this stuff ages ago but not used it, causing me to forget it.

    I will be nice not to have to use jQuery to do alternate table row colors.

  33. 33

    Richard Shepherd

    March 31, 2011 11:02 am

    Really interesting thoughts, Michel. Thanks for sharing.

  34. 34

    Richard Shepherd

    March 31, 2011 11:08 am

    Hi Frederick,

    I use these techniques every day on a site with millions of visitors each month. The magic ingredient is JavaScript, which helps older browsers pull their socks up :) It’s a shame that you feel you can’t use pseudo-classes because I think they’re very useful, and I’ve never run into any problems.


  35. 35

    Awesome tutorial…. Must Bookmarked

  36. 36

    Great article, thanks for sharing all this technics.
    There is a small mistake(mistype) I think. At the section “4. Negation Pseudo-Class”, where you wrote about “input:not([type=submit]) { … } and input:not(disabled) { … }”, you wrote : “The second selects all input elements that are not enabled;”. But it selects all input elements thare not disabled, am I right?

  37. 37

    Microsoft is pushing towards their Windows 7 platform and the support for XP has ended, so they’re not going to bother having an IE9 browser on XP, they’ll lose some market share on this.

  38. 38

    Vancouver photographer

    April 1, 2011 2:58 am

    Fantastic post! Definitely going to give the tip about using the a element linking a whole selection a try. As well as the ‘only’ type. Thanks so much for the detail and clarity!

  39. 39

    When the hell is microsoft going to eat there shit completely duh and what about ie9 is not working on xp lolx more than windows 7 uses xp now what ????????

  40. 40

    Hetal Sindhwad

    April 1, 2011 4:21 am

    Nice tutorial….such a brainstorming of school algebra…..I would like to know one thing above u have mentioned that unlike array in css first value of “n” is “1” and not “0”, but later in examples shown u have put “0” as first value of “n”…reallly cant get on this cud u just clarify…thanks

  41. 41

    But Firefox 4 also use hardware acceleration on Win XP. And maybe I’m wrong, but I think I read, that Firefox uses the same interfaces, that IE9 could use on XP.

    So in this case I think it’s more a political decision than a technical one.

  42. 42

    I dont have the motivation to learn css3 because IE dont support it, whats the point I hate having to correct code for cross browser at the moment with css2. someone tell me how to get the motivation, i havent even read this article.

    Sorry guys


  43. 43

    Lee Agosila

    April 3, 2011 5:29 pm

    thanks for this Smashing Magz!! =)

  44. 44

    Daniel Matei

    April 4, 2011 12:23 am

    Great article! Thanks for doing this!

  45. 45

    My point still stands, even if people vote my post down. CSS3/HTML5 stuff is great but it’s even harder now to guarantee a client how a website is going to behave than in the dreaded IE6 era.

  46. 46

    Question: This may be a small thing, I’m new to CSS3… I understand these as “:root” and “:nth-last-child(n)” but what what are “E:root” and “E:nth-last-child(n)” does the the “E” stand for “Example”?

  47. 47

    E stands for element, I suppose.

  48. 48

    Crap. Another bad release from an evil company… Die, Internet Explorer, die!

  49. 49

    oh ! thank you ! :)

  50. 50

    Great Post!! Keep on posting…..

  51. 51

    great stuff – I will definitely check a lot of those out on my next frontend design project.

    Is there a jquery plugin that supports all of those css3 pseudo-elements for ie8 an below?

  52. 52

    Petr Stojan

    April 7, 2011 9:34 am

    Great article – I came to bed at 5 AM. 5 coffees today.

  53. 53

    Kashif M Qasim

    April 8, 2011 2:44 am

    Great article Richard! Keep them coming.

  54. 54

    Capi Etheriel

    April 8, 2011 10:39 am

    In your example, you say you use the following code:
    form:nth-child(-n+3) label { display: none; }
    But this will actually pick the three first elements and and look for their labels. If you want to select the three first children of the form, you need to add a space there:
    form :nth-child(-n+3) label { display: none; }

  55. 55

    Chris Nager

    April 8, 2011 1:30 pm

    ul:hover li:not(:hover) { opacity: .1; }

    I used the “:not ” pseudo-class and absolutely love it!

  56. 56

    Alexander Filatov

    April 10, 2011 11:37 pm

    A very interesting article! Definitely bookmarked under “useful”! Thank you.

    I think the main question you have to ask yourself is what is your target audience? If you want to target the latest and greatest – use the pseudo-classes and something like Selectivizr for “almost” latest and greatest, while making sure that the users of older browsers know why their page is messed up and that they should upgrade.

  57. 57

    Danilo Ramos

    April 12, 2011 5:52 am

    The pseudo class :target don’t work in Internet Explorer AAAAAAArgh !

  58. 58

    mhadi oedram

    April 12, 2011 8:12 am

    I wish there was a browser compatibility chart for this article

  59. 59

    geirge gershen

    April 14, 2011 7:31 pm

    No async on the GA tracker?

  60. 60

    “we can hope to see IE9 as the dominant Windows browser in the near future”

    Doubt it, not while XP remains the dominant Windows OS version.

  61. 61

    Why did you put block elements [div, h1, h2, p] in inline element a?
    Was that for semantic code?

  62. 62

    Note that it is an W3C Proposed Recommendation and until it is in the final version it is not an ideal solution to use them. Even more if you want to build an website that complies to the WCAG guidelines

  63. 63

    Still an amazing read, thanks!

  64. 64

    Hey Richard
    already red comments, but there’s still a question.

    u said using “fieldset:nth-last-child(2) input:nth-last-of-type(3) {border-radius: 10px; }” would select “Card number” input in this example.
    Counted it in src, and – for me – it selects:
    [Line 77] input named Security Code

    Could you tell me, why im wrong, please?
    I’m still in apprenticeship and reading this, really makes me feel becoming better with css :)


↑ Back to top