Advanced CSS Selectors with Practical Examples

The contents of this article may be out of date. It has been archived and will no longer be updated, comments are closed and the page is provided for reference purposes only.

Selectors allow you to define the parts of your HTML documents you want to have styles applied to. CSS2 and later CSS3 brought with them a host of new selector specifications, designed to allow greater access to the elements and parts of those elements that make up a webpage. These new rules allow greater flexibility and accuracy in defining exactly which parts of your page get styled. Here we will look some of the new selectors and provide some real word examples of how they may be useful.

Combinations

Basic CSS allows you to apply styles to Elements, ID’s and Classes. Combinations can be used to drill down to specific parts of your document. The combinators allow you to define styles that are based on a more complex rule that will be applied to more specific elements.

p a {text-decoration: none; }

This rule will affect all links inside paragraphs only. This is very useful to apply a style to links within text and is a basic example of how combinations can be used.

Adjacent Sibling Combinator

The adjacency combinator (a plus sign, +) allows you to style an element if it has been directly preceded by another specified element. This is handy when working out margins and padding. For instance, you may give your headings large margins so they stand out from normal text, but if two headings come one after the other, you may want to control the margin between them as a special case, like so:

h1, h2 {margin: 2em 0; }
h1 + h2 {margin-top: 1em; }

Child Combinator

The child combinator (the greater-than symbol, >) can be used to combine two elements, and will only be applied if the second element comes directly after the first. It looks like this:

p > em {font-weight: bold; }

This will affect all <em> elements which occur as children of paragraphs, but not those that have another parent element in-between (which would make the em a grand-child or more).

Universal Selector

The universal selector (denoted by a asterisk, *), affects every element on a page and is commonly seen improperly used to reset margins and padding. In most cases it can be omitted as it is implied by inheritance. The two rules below have the same meaning:

* p {text-indent: 2em; }
p {text-indent: 2em; }

It becomes useful when used with the child combinator, as it can take the place of any element which may occur in between two others, as in:

p > * > em {font-weight: bold; }

A rule like this would allow the second em element in our example above to be styled, but not an em which was inside a further element.

Attribute Selectors

This CSS2 attribute selector (square brackets) matches any element that has a title attribute specified. The contents of the title attribute is irrelevant in this case. The attribute name is an identifier, so should not have quotation marks around it.

In this example we want a dotted bottom border for any element that has a title attribute, to alert the reader that there’s an advisory title available which may be displayed as a tool-tip. We’ll also change the mouse cursor for those elements, to emphasise that the tool-tip is meant as some form of help to the reader.

[title] {
  border-bottom: 1px dotted;
  cursor: help;
}

Taking this a step further, you can select an element that has a precise value specified:

a[href="http://www.yourdomain.com/"] {font-weight: bold; }

This rule will match a link with the exact href of ‘http://www.yourdomain.com/’. Note the value is wrapped in double-quotes as it’s a value not an identifier.

There’s also a basic pattern-match selector which can look for a single word in an attribute’s value. If the value is a space-separated list (a sentence, in other words), you can write a rule to look out for certain words.

a[title~="External"] {background: url(outside-link.gif); padding-left: 15px; }

The operator in use here is a tilde (~) followed by an equals. It would match something like

<a href="http://www.google.com" title="External link to Google">Google</a>

The above example will add a graphic to all links that contain the word “External” in its title.

a[href^="http:"]

This CSS3 attribute selector matches link elements whose href attribute value starts with the string “http:”. This could be a better way to style to only external links, your internal links do not usually need the full path only a relative path.

a[href^="mailto:"]

This CSS3 attribute selector matches link elements whose href attribute value starts with the string “mailto:”. Here we can add style to links that will open your mail client.

img[src$=".png"]

This CSS3 attribute selector matches image elements whose src attribute values ends with the string “.png”.

input[name*="choice"]

This CSS3 attribute selector matches ANY input element whose name attribute value contains the string “choice”.

Pseudo-Classes

There are some parts of a document that don’t exist as elements by themselves — they are merely parts of elements, or elements in a particular state, like the first line of a paragraph. CSS pseudo-classes and pseudo-elements allow access to these otherwise inaccessible parts.

Most commonly seen is the link pseudo-classes, :link, :visited, :active and :hover. These are a good introduction as to how pseudo-classes work. A link becomes classed with a:active when it is clicked on, but there is nothing in the HTML document that makes it so.

While :hover has been seen before on links, the specifications allow this class to be applied to any element. This means you can highlight a paragraph or quotation when the user mouses over it. There are many interesting applications for this property. Set it up like this:

p:hover {border: 1px solid #0c0; }

The :focus class is activated when a user clicks on or tabs to an element, usually a form field or link. Highlighting a form field while the user is filling it in is a nice interface effect.

input:focus {background: #ffe; border-color: #c00; }

CSS allows access to child elements based on their position inside a parent. CSS2 included the :first-child class, which was added to an element if it was the first tag inside another element. The selector below would embolden the first paragraph in the example HTML, but not to the second one:

div#intro p:first-child {font-weight: 700; }

<div id=“intro”>
  <p>Here is the first paragraph.</p>
  <p>Subsequent paragraphs not affected.</p>
</div>

The :first-line element can be used with any block-level tag, and applies to the first line of text running across the screen. If the window gets smaller and some words drop down onto the next line on the screen, they are no longer part of the :first-line. This element is useful to bring in the commonly-used practice of capitalising the first few words of an opening paragraph:

p:first-line {text-transform: uppercase; }

Similarly, the :first-letter pseudo-element gives access to the opening letter of any element. This is useful in creating drop-caps — the large letters normally seen at the start of newspaper stories. If the first character in the element is an opening-quote mark, it is counted as part of the :first-letter, along with the letter that comes after it.

p:first-letter {font-size: 200%; }

These rules can be combined. The below example will only cause drop-caps to be used on the first paragraph:

div#content p:first-child:first-letter {font-size: 200%; }

CSS3 takes things a step further, by adding the :last-child and :nth-child classes. The former is simply the last element to occur within its parent. The :nth-child element is more complex — allowing access to either a numbered element, or allowing you to cycle through multiples of a number. This means you could style every third row of a table differently, for instance.

The example below will match every second row in a table, causing the zebra effect as seem in Apple’s iTunes interface.

table tr:nth-child(odd) td {background: #f1f5fa; }

In the example below, we will produce the same effect on an unordered list but instead of using odd or even we use numbers, this could as easily only be applied only to the 3ed element by replacing (2n+1) with (3). Note the :first-child is numbered 1.

ul:nth-child(2n+1) li {background: #f1f5fa; }

This article was posted on 10 July 2009 in CSS

comments

What you have had to say about all this...

Excellent stuff, and thank you. <waves cheerfully>

- Ivo Roper

I do not want to repeat this website, but I actually just like the design. Could you comment on which template you are using or is this custom designed?

- driving games

That's the end of this article. I hope you found it useful. If you're enjoyed this article why don't you have a look around the archives, where you can find some more tutorials, tips and general ramblings.