Advanced Selectors
Selectors are the way you reference the parts of your HTML documents with the styles you want to have applied to them. CSS2 and 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 each and every webpage. These new syntax rules allow greater flexibility and accuracy in defining exactly which parts of your page get styled.
This page was last updated on 2012-08-21
Browser Compatibility Note:
» Firefox, » Mozilla, IE5/Mac, NN6, Opera 5 and » Safari all support the CSS2 selectors. However, almost none of these selectors are supported by Internet Explorer 6 on Windows. This makes it a poor strategy to define critical pieces of CSS while using them.
They are therefore more suited to adding finishing touches for browsers that support them — small design finesses and useful but non-critical visual feedback nuances.
Combinators
The advanced combinators allow you to define styles that are based on a more complex rule that will be applied to more specific elements. Originally, it was possible to get to descendant-elements through contextual styles. For instance:
p em {font-size: larger; }
This rule will affect all em
elements inside paragraphs. This is very useful, but also relatively simplistic. Combinators allow you to state the required relationship between two elements.
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 comes in very handy when working out margins and such. 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: 3em 0; }
h1 + h2 {margin-top: 1em; }
Child Combinator
The child combinator (denoted by 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-size: larger; }
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). In the example below, the first em
element would be styled, but the second would not, as it is inside an a
element — and therefore not directly below the p
element:
<p>Do <em>not</em> visit <a href="index.html"><em>this</em> page</a>!</p>
Universal Selector
The universal selector (denoted by a star, *), affects every element on a page.
* {color: #bb0; }
IE6 supports the universal selector. In most cases it can be omitted as it is implied by inheritance. The two rules below are equivalent:
* p {text-indent: 2em; }
p {text-indent: 2em; }
However, it does become useful when used in concert 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-size: larger; }
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, as in a case like
<p>Seriously, <strong>do not visit <a href="index.html"><em>this</em> page</a>!</strong></p>
It should be apparent that you can chain any of these rules together into a single complex rule.
Attribute Selectors
CSS2 also allows you to apply styling to an element based on the attributes it has defined in it, or even based on the values of these attributes. Firstly, to select the elements with an attribute defined, you infix the attribute name surrounded by square brackets:
abbr[title] {border-bottom: 1px dashed #0c0; }
This would apply styling to all abbr
elements which have the title
attribute, whatever its value. Taking this a step further, you can select an element that has a precise value specified:
a[href="http://www.yourhtmlsource.com/"] {font-weight: bold; }
This rule will match a link with the exact href
of ‘http://www.yourhtmlsource.com/’. Note that the value is wrapped in double-quotes.
While this could quickly make your CSS file very big and clumsy-looking, it’s undoubtedly a useful power to have at your disposal. This selector comes into its own when you’re styling an XML document, where much of an element’s information may be written in as an attribute value.
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~="Mail"] {text-decoration: none; }
The operator in use here is a tilde (~) followed by an equals. It would match something like
<p>Send me <a href="mailto:address@server.com"
title="Mail me">email</a>.</p>
You can link many attribute selectors into a single rule to find a specific element:
p[align="right"][class="intro"] {line-height: 1.8em; }
Pseudo-classes
Despite all the different elements you can get to with the selectors above, there are 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, or a form field that has been focused on. CSS pseudo-classes and pseudo-elements allow access to these otherwise inaccessible things.
You may have already seen the link pseudo-classes, :link, :visited, :active and :hover. These serve as 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.
Dynamic Pseudo-classes
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; }
These pseudo-classes are not what’s called ‘mutually exclusive’ — that is, an element can have one or more of these classes activated at once. To style an input
that is focused and being hovered on, write
input:focus:hover {background: gold; }
Structural Pseudo-classes
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 add style to the first paragraph in the example HTML, but not to the second one:
div#intro p:first-child {font-size: 110%; }
<div id="intro">
<p>The opening paragraph.</p>
<p>The next paragraph</p>
</div>
CSS3 took this two steps 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.
In the examples below, first I style the fifth paragraph in a blockquote
. The second selector will match every second row in a table. Remember that the :first-child is numbered 1.
blockquote p:nth-child(5) {color: gold; }
table tr:nth-child(2n+1) td {background: silver; }
To simplify the calculation, you can use the values odd and even: p:nth-child(odd).
Pseudo-elements
Pseudo-elements allow you to style fictional elements which don’t actually exist in the HTML code, like the first line of a paragraph. Pseudo-elements can only be the subject of the selector (the right-most element).
Textual Pseudo-elements
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:
div#content p:first-child::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%; padding: 3px; border: solid black; border-width: 1px 0 0 1px; }
Obviously, ::first-letter occurs inside ::first-line, so it will inherit and override any properties set in the first line element. Also note that these two elements are supported by IE on Windows. Hooray for that.
sourcetip: Before the CSS3 Selectors specification, pseudo-elements were appended with a single colon in between, like p:first-line. To make the distinction between classes and elements, this was revised to two colons, as in p::first-line.
There are even more new selectors in CSS3 that I haven’t mentioned here — primarily because browser support for them is a way off. Still, they’re interesting to know about, so you can catch them in the » CSS3 Selectors spec.