Advanced CSS selectors



In our [CSS basics] article, we introduced the most basic of CSS selectors: element, class and id selectors. With these selectors you can accomplish a lot, but this certainly isn’t the be all and end all of selectors — there are other selectors that allow you to select elements to style based on various more specific criteria, and we’ll look at most them throughout the course of this article.

Note: We are saying “most” here because although most modern browsers support all the selectors listed in the CSS3 selectors module, new selectors are being added/modified all the time (keep checking the CSS4 selectors draft for updates). We will aim to update this resource with new selectors as and when they receive more widespread browser support.

You will see many of these selectors used throughout our articles as you read on. Don’t worry if you don’t understand them all immediately: keep coming referencing this article if you need more help.

Universal selectors

Universal selectors select every element on a page. For example, the following rule says that every element on the page should be given a solid 1 pixel black border:

* {
  border: 1px solid #000000;

Attribute selectors

Attribute selectors allow you to select elements based on the attributes they contain. For example, you can select every <img> element with an alt attribute using the following selector:

img[alt] {
  border: 1px solid #000000;

Note the square brackets.

Using the above selector, you could perhaps choose to put a black border around any images that have an alt attribute, and style other images with a bright red border —  this would be a useful technique to employ in accessibility testing.

Selecting by attribute value

Attribute selectors instantly get more useful when you consider that you can select by attribute value, not just attribute name. The following rule selects all images with an src attribute value of alert.gif:

img[src="alert.gif"] {
  border: 1px solid #000000;

Again this can be useful for debugging purposes, and perhaps styling important icons or links without needing to add additional classes/IDs.

Note that this is not supported by IE6 and below.

Selecting based on substrings within the attribute value

This is where attribute selectors become even more useful. To start with, you could select and style our <img src="alert.gif"> element using the following:

img[src^="alert"] {
  border: 1px solid #000000;

The ^ character dictates that this selector should select <img> elements only if they have the string alert at the start of the src attribute value.

Next, we could also select our <img src="alert.gif"> element using this:

img[src$="gif"] {
  border: 1px solid #000000;

The $ character dictates that this selector should select <img> elements only if they have the string gif at the end of the src attribute value. This is really useful for styling links that point to specific types of resources, like PDFs or word documents.

Finally, we could select our <img src="alert.gif"> element like this:

img[src*="ert"] {
  border: 1px solid #000000;

The * character dictates that this selector should select <img> elements only if they have the string ert anywhere within the src attribute value.

Note that these are not supported by IE8 and below.

selecting based on delimited items within the attribute value

If you had an element on a page with a number of classes applied to it, for example:


You could select it using any of the following selectors:


The ~ character dictates that these selectors should select an <article> element whose class attribute value is a list of whitespace-separated values, but only if one of those values is the value given inside the quotes.

Now lets look at an element on a page with an ID value in the form of hyphen-separated list:

<article id="english-daily-feature"></article>

You could select it using the following selector:


The | character dictates that this selector should select an <article> element whose id attribute value is a list of hyphen-separated values, but only if the leftmost one of those values is english.

Note that these are not supported by IE8 and below.

Child selector

You can use a child selector to select specific elements that are children of other specific elements. For example, the following rule will turn the text of <strong> elements that are children of <h3> elements blue, but no other <strong> elements:

h3 > strong {
  color: blue;

Note that child selectors are not supported in IE 6 or below.

Note also that the > character is often referred to as a combinator in this context — it combines multiple elements together in one selector.

Descendent selector

Descendent selectors are very similar to child selectors, except that child selectors only select immediate descendents; descendent selectors select matching elements anywhere in the element hierarchy, not just direct descendents. Let’s look at what this means more carefully. Consider the following HTML snippet:

    <p>In this paragraph I will say goodbye</p>.

In this snippet, the <div> element is the parent of all other elements. It has two children, a <p> and an <article>. The <article> element has a single child element: another <p>.

You could use a child selector to select just the <p> immediately inside the <div>, like so:

div > p {

If you instead used a descendent selector, as follows:

div p {

Both of the <p> elements would be selected.

Adjacent sibling selector

This selector allows you to select a specific element that comes directly after another specific element, on the same level in the element hierarchy. Take the following example:

<h2>My heading</h2>
<p>My first paragraph</p>
<p>My second paragraph</p>
<p>My third paragraph</p>
<p>My fourth paragraph</p>
<p>My fifth paragraph</p>

If you wanted to select just the <p> element that comes immediately after the <h2> element (and any other such <p> elements that might appear later in the document) you could use the following rule:

<code>h2 + p {

Note that the adjacent sibling selector is not supported in IE6 or below.

Note also that the + character is often referred to as a combinator in this context — it combines multiple elements together in one selector.

General sibling selectors

The general sibling selector is very similar to the adjacent sibling selector, except that it allows you to select all siblings of the specified element type, not just the one immediate next to the element on the left hand side. the syntax looks like this:

<code>h2 ~ p {

Returning to our previous example, this ruleset would select all five paragraph elements, not just the first one. It would also select the paragraph shown below:

<h2>My heading</h2>
<h3>My sub heading</h3>
<p>My paragraph</p>

Note that the general sibling selector is not supported in IE8 or below.

Note also that the ~ character is often referred to as a combinator in this context — it combines multiple elements together in one selector.


Pseudo-classes are used to provide styles not for elements, but for various states of elements.

Link and user action pseudo-classes

The most common pseudo-classes you’ll come across is those used to style link states (you’ll see these in full usage in [Styling lists and links]):

  • :link — the normal, default state of links, just as you first found them.
  • :visited — selects links that you have already visited in the browser you are currently using.
  • :focus — selects links that currently have the keyboard cursor within them.
  • :hover — selects links that are currently being hovered over by the mouse pointer.
  • :active — selects links that are currently being clicked on.

Note that the last three of these (these are the “user action pseudo-classes” — the first two are the link pseudo-classes) can be used the style states of pretty much any element it would make sense to use them on in a user interface. For example, you might want a form input to adopt a different style when it is tabbed into, or you might want an information box to appear only when a certain part of the screen is moused over.

Let’s look at some examples. The following CSS rules make it so that by default, links are blue (the default in most browsers anyway). When hovered over, the default link underline disappears. We want the same effect when the link is focused via the keyboard, so we duplicate the :hover rule with :focus . When a link has already been visited, it turns grey. Finally, when a link is active, it is bolded, as an extra clue that something significant is happening.


a:link {
 color: blue;

a:visited {
 color: gray;

a:hover, a:focus {
text-decoration: none;

a:active {
 font-weight: bold;

Take care if you don’t specify these rules in the same order as they are shown in above, otherwise they might not work as you expect. This is due to the way specificity causes later rules in the stylesheet to override earlier rules. You’ll learn more about specificity in Inheritance and cascade.

As another example, the :focus pseudo-class is also useful as a usability aid in forms. For example, you can highlight the input field that has the active blinking cursor inside it with a rule like this:


input:focus  {
  border: 2px solid black;
  background color: lightgray;

The negation (not) pseudo-class

The negation pseudo-class can be used to explicitly apply styles to elements that are not selected by a simple selector. Let’s say we wanted to apply some styling to a number of content blocks, all except one. The blocks could look like so:

<section id="abstract"> ... </section>
<section id="experiment"> ... </section>
<section id="tests"> ... </section>
<section id="results"> ... </section>
<section id="conclusion"> ... </section>
<section id="references"> ... </section>

We could apply the styling to all sections except the references by doing this:

  1. abstract, #experiment, #tests, #results, #conclusion {


Or instead, we could use the negation selector, like so:

section:not(#references) {



Which is much shorter and simpler.

Note: The negation selector is not supported by IE8 and below.

The language (lang) pseudo-class

The :lang pseudo-class selects elements whose languages have been set to the specified language using the lang attribute. For example, the following element:

<p lang="en-US">A paragraph of American text, gee whiz!<p>

Could be selected using the following:

p:lang(en-US) {

The target pseudo-class

The target pseudo-class allows you to select an element if it is the target of the current page URL. This is really useful and allows for some cool effects, because it effectively allows you to set styles to be applied when links are clicked. For example:

<a href="#target">Click me</a>

<div id="target">Woot!</div>

Here we have a simple link followed by a <div> — the link references the <div> via it’s ID. The current URL only targets the <div> upon the link being clicked. To style the <div> only when the link is clicked, you could use the following:

div:target {

To see a much more involved example of :target usage, read CSS3 target-based interfaces by Corey Mwamba.

UI element state pseudo-classes

These pseudo-classes are all concerned with styling advanced states of UI elements. You’ll most commonly use them to style HTML form elements, particularly when some of the new features of HTML5 forms are being used, such as built in validation (see [HTML5 form additions] for more details).

Let’s say we are styling a basic form input with a valid attribute for validation:

<input type="text" required>

We could style it only when the information entered into it is valid or invalid using

input:valid {}


input:invalid {}

We could style it depending on whether it is enabled (default) or disabled (using the disabled attribute), using

input:enabled {}


input:disabled {}

Finally, we could style a checkbox only when checked like so:

input[type=”checkbox”]:checked {}


Structural pseudo-classes

Structural pseudo-classes are advanced selectors allowing you to target specific elements based on their position in the document hierarchy. These were introduced in CSS3, and build on selectors we’ve already looked at, such as the adjacent sibling selector.

:root selects the root element of the document, which is usually the <html> element. For example:

html:root{ ... }

<p>:nth-child(n) allows you to select a repeating pattern of elements inside an continuous set of like elements, for example several list items, or several paragraphs or articles next to one another. Let’s look at an example:


n is set to the pattern we want to select. In this case, to select list items we do this:


To select just the odd or even list items, we’d use these:


Or we could use


To do the same thing.

Let’s look at some other formula examples:

  • li:nth-child(5): select the 5th adjacent list item
  • li:nth-child(4n+1): select every 4th list item starting at 0, and then add 1 to each result. So numbers 1, 5 and 9.
  • li:nth-child(3n-2): select every 3rd list item, and subtract 2 from each result. So numbers 1, 4 and 7.

Next let’s move on to nth-last-child(n). This does the same thing as nth-child(n), but it counts from the last element in the sequence, not the first.

nth-of-type(n) and nth-last-of-type(n) do pretty much exactly the same thing as nth-child(n) and nth-last-child(n), but there is one important difference: the former two ignore any rogue elements interspersed with the repeated sequence of like elements because they select by type of element, not child number. The latter selects by child number.

Let’s have a look at another example:

  1. <article> ... </article>
  2. <article> ... </article>
  3. <article> ... </article>
  4. <article> ... </article>
  5. <article> ... </article>
  6. <blockquote><p> ... </p></blockquote>
  7. <article> ... </article>
  8. <article> ... </article>
  9. <article> ... </article>

In this example we’ve got a <element> with eight child <article> elements, and a single <blockquote> element sat in the middle of them: this is child number six. There are a total of nine child elements.

If you used article:nth-child(2n+0) as your selector, to select all the even-numbered children of the <div>, you’d select only the <article>s in positions 2, 4 and 8: the <blockquote> (position number six) wouldn’t be selected because it is not an <article>.

If you used article:nth-of-type(2n+0) as your selector, you would select the <article>s in positions 2, 4, 7 and 9: this is because this selects by the type of element, not the child position, therefore in this case the <blockquote> is completely ignored and the even numbered <article>s are selected. Yes, two of them are odd numbered according to my original numbering scheme because in reality the <blockquote> exists and offsets their position, but article:nth-of-type(2n+0) ignores the <blockquote>, effectively counting positions 7 and 9 as 6 and 8.

Next, we’ll have a look at :first-child and :last-child — these pseudo-classes select only the first or last instance of an element that is the first or last child element of its parent. So, considering the above example again, we could use the following to select – respectively – the first and last <article> element:


article:first-child { ... }

article:last-child { ... }

blockquote:first-child would select nothing, because the first child is not a <blockquote>.

first-of-type and last-of-type again work in a very similar way, but they select based on the type of element, not the position of child it is. So article:first-of-type would select exactly the same <article> element as article:first-child, but blockquote:first-of-type would select the single <blockquote> in the example, because it is the first of its type, even thought it is the 6th child.

There are a few others to quickly consider:

  • only-child: Selects an element only if it is the only child of it’s parent, eg article:only-child wouldn’t select anything in our example above, because there is more than one <article> child.
  • only-of-type: Selects an element only if it is the only sibling of it’s type inside the parent element. eg blockquote:only-of-type would select the <blockquote> in the above example because it is the only one of its type present.
  • empty: selects an element only if it has no children whatsoever (including text nodes). For example div:empty would select <div></div>, but not <div>1</div> or <div><p>Hi!</p></div>


Pseudo elements differ from pseudo-classes in that they don’t select states of elements; they select parts of an element.


First of all, you can select the first letter inside a given element using the following rule:

p:first-letter {
  font-weight: bold;
  font-size: 300%
  background-color: red;

The first letter of every paragraph will now be bolded, 300% bigger than the rest of the paragraph, and have a red background. This is a good start towards creating a decent drop cap effect.


To make the first line of every paragraph bold, you could use the following rule:

p:first-line {
  font-weight: bold;

Generated content using :before and :after

You can use the :before and :after pseudo-elements to specify that content should be inserted before and after the element you are selecting. You then specify what content you want to insert or generate. As a simple example, you can use the following rule to insert a decorative image after every link on the page:

a:after {
  content: " " url(flower.gif);

You can also use the attr() function to insert the values of attributes of the elements after the element. For example, you could insert the target of every link in your document in brackets after each one using the following:

<code>a:after {
  content: "" "(" attr(href) ")";

This is a great technique to use in a print stylesheet, where you want to just show the URLs in the document rather than have them hidden inside links (useless on a printed page).

You can also insert incremented numerical values after repeating elements (such as bullets or paragraphs) using the counter() function — this is explained in much more detail in [Automatic numbering with CSS counters] by David Storey.

These selectors are not supported in IE 7 or below. Also note that you shouldn’t insert important information with CSS, or that content will be unavailable to assistive technologies or if a user chooses not to use your stylesheet. The golden rule is that CSS is for styling; HTML is for important content.

CSS3 pseudo-element double colon syntax

Please note that the new CSS3 way of writing pseudo-elements is to use a double colon, eg a::after { ... }, to set them apart from pseudo-classes. You may see this sometimes in CSS. CSS3 however also still allows for single colon pseudo-elements, for the sake of backwards compatibility, and we would advise that you stick with this syntax for the time being.

Leave a Reply