Ashley Sheridan​.co.uk

Getting the most out of CSS selectors

Posted on

Selectors in CSS are one of the most powerful and useful features you have at your disposal, and yet seem to be little used to its potential. Complex selectors solve the problem of targeting specific elements on a page (and in some browsers, elements that fall under certain conditions as well)

One alternative to selectors which some developers find popular is to give every element that needs to be styled a class, and then in the CSS apply the styles by class. This is fine for simple objects on your page, but if you've got an element that consists of several smaller parts, then you end up with CSS class fever, where every element on the page has it's own class, for no reason other than you don't know better.

Consider a simple table that's a schedule for this week. Now, there are several parts to this, and you'll want the whole thing to look just right. Thse HTML for that table would look like this:

<table id="schedule"> <tr> <th></th> <th>Monday</th> <th>Tuesday</th> <th>Wednesday</th> <th>Thursday</th> <th>Friday</th> </tr> <tr> <th><abbr title="ante meridiem">AM</abbr></th> <td>meeting</td> <td></td> <td><strong>important meeting</strong></td> <td></td> <td><em>out of office</em></td> </tr> <tr> <th><abbr title="post meridiem">PM</abbr></th> <td></td> <td><em>meeting</em></td> <td><strong>important meeting</strong></td> <td></td> <td><em>out of office</em></td> </tr> </table>

In itself, it has a simple layout, and a good use of heading tags puts the information within it into context. With only an id attribute given to the table, you can style the entire thing exactly as you need, without having to add a class to everything:

table#schedule { border: 2px solid #000; border-collapse: collapse; width: 600px; color: #000; font-family: Arial, sans-serif; } table#schedule th { font-weight: bold; text-align: center; width: 100px; background-color: #999; color: #fff; border: 0px none; } table#schedule th { border: 0px none; } table#schedule em { background-color: #8f8; display: block; } table#schedule strong { color: #f88; display: block; }

And this is how it looks once applied:

Monday Tuesday Wednesday Thursday Friday
AM meeting important meeting out of office
PM meeting important meeting out of office

There's only one id used in the whole excerpt, not a class in sight, and still everything is styled individually. You can take this as far as you need it, with nested elements to any depth you need. Of course there are times you may need to define extra classes, but this example should show you that it's not necessary at all.

Selectors can also do other interesting things too. With CSS3, a lot of browsers have added support for psuedo-elements, which allow you to create CSS matching rules based on all sorts of things, from attribute values to active states:

Pseudo-ElementActs on
body:first-childmatches the first element after the <body> tag
p:first-lettermatches the first letter of a paragraph, essentially wrapping it in invisible tags for you to style
li:nth-child(n|n+x|odd|even)matches every nth, nth+x, odd or even item in a list. This is useful for styling alternate rows or columns in a table, etc)
a[name]matches all anchors in the document because an anchor has the name attribute
p[class*=ab]Matches any paragraph that has a class containing the phrase 'ab', i.e. 'cab','abbreviation', etc
a[href^=http]Matches all links that have absolute URLs, useful for highlighting external links if your internal links aren't absolute also
a[href=$=.txt]Matches all links in the document that point to text files
input[name=email]matches any input element with the name 'email'. This can be used to match any attribute on an element.
body > pWould match all paragraph tags that are chidren of the body, note that this won't match <body><div><p> as then it becomes what is known as a descendent and not a child.
p + tableMatches a table that appears directly after a paragraph, note that the paragraph must be closed to match, otherwise it becomes a child and not a sibling.
p ~ tableAs the one above, but the table doesn't have to immediately follow the paragraph, there can be other elements in between.
img:not(.thumb)Matches any image that does not have the thumb class.

There are far more, but these are the ones that I've found most useful. Bear in mind though that some of these won't work in older browsers (IE versions less than 9) but have good support in Fx, Opera, Safari, Chrome, Konqueror, Galleon and Epiphany. There's a good (although out of date) list of compatibility with various browsers at kimblim.dk/css-tests/selectors/.

Hopefully this will stop you from getting CSS class fever and use selectors more efficiently. You'll soon find that the layout of your CSS files improve as well, and they'll be easier to read and manage.