CSS 2.1 selectors, Part 2

This is the second part of a three-part article series that explains the selectors that are available in CSS 2.1. Part 1 is about the more basic stuff like type selectors, class and id selectors, the universal selector, and simple selectors.

In this part I will take a closer look at the more advanced selectors, not all of which are yet fully supported in all major browsers. Support is getting better though, so learning about the selectors that are described in this article is time well spent.


Combinators are used to separate the two or more simple selectors that make up a combined selector. The available combinators are whitespace (any number of tab, space or other whitespace characters), >, and +. What each combinator does is described in the next few sections.

Descendant selectors

A descendant selector is made up of two or more simple selectors separated by whitespace. It matches elements that are descendants of an element that matches the first simple selector. For example, the selector in this rule would match all p elements that are descendants of a div element:

div p { color:#f00; }

Each of the selectors that form a descendant selector can be a simple selector of any form. The selector in the following rule matches all p elements with a class name of info that are contained by an li element that is contained by a div element with the id myid.

div#myid li p.info { color:#f00; }

Descendant selectors allow you to target elements without giving them a class name or an id, which in turn helps keep your markup clean. Let’s assume you have a navigation list consisting of the following markup:

<ul id="nav">
	<li><a href="#">Link 1</a></li>
	<li><a href="#">Link 2</a></li>
	<li><a href="#">Link 3</a></li>

To target only those list items and links that are contained within the navigation list you could use the following CSS:

#nav li { display:inline; }
#nav a { font-weight:bold; }

These rules will not match any other list items or links in the document. Compare that to giving a class name to each list item and link, and you’ll realise how much cleaner your markup can become when you use descendant selectors.

Child selectors

A child selector targets an immediate child of a certain element. A child selector consists of two or more selectors separated by a greater than sign, “>”. The parent goes to the left of the “>”, and whitespace is allowed around the combinator.

This rule will affect all strong elements that are children of a div element:

div > strong { color:#f00; }

Only strong elements that are direct descendants of div elements will be targeted by this rule. If there is any other element between the div and the strong elements in the document tree, the selector will not match. In the following example, only “Text one” will be affected by the above rule:

	<strong>Text one</strong>
	<p><strong>Text two</strong></p>

Adjacent sibling selectors

An adjacent sibling selector is made up of two simple selectors separated by a plus sign, “+”. Whitespace is allowed around the adjacent sibling combinator. The selector matches an element which is the next sibling to the first element. The elements must have the same parent and the first element must immediately precede the second element:

p + p { color:#f00; }

If applied to the following example, the above rule will only affect “Paragraph two”:

	<p>Paragraph one</p>
	<p>Paragraph two</p>


I decided to mention grouping at this point, because one common mistake I see people making when they are learning CSS is related to grouping combined selectors.

To apply the same rules to elements matched by several different selectors you can group them into a comma-separated list instead of repeating the declarations for each selector. The mistake many make is to not list the full selectors. Assume that you have the following markup:

<div id="news">
		<li>Item 1</li>
		<li>Item 2</li>

Now, say you want to apply the same amount of margin to level 3 headings and unordered lists, but only if they are in the div element whose id is “news”. Here is the wrong way:

div#news h3, ul {
	margin:0 2em;

This will affect both h3 and ul elements in div#news. The problem is that it will target all ul elements in the document, not only those in div#news.

Here is the correct way of grouping the selectors in this case:

div#news h3,
div#news ul {
	margin:0 2em;

So, when grouping selectors, remember to fully specify each selector.

Attribute selectors

Attribute selectors match elements based on the presence or value of attributes. There are four ways for an attribute selector to match:

Matches elements that have an att attribute, regardless of its value.
Matches elements that have an att attribute with a value of exactly “val”.
Matches elements whose att attribute value is a space-separated list that contains “val”. In this case “val” cannot contain spaces.
Matches elements whose att attribute value is a hyphen-separated list that begins with “val”. The main use for this is to match language subcodes specified by the lang attribute (xml:lang in XHTML), e.g. “en”, “en-us”, “en-gb”, etc.

Some examples then. The selector in the following rule matches all p elements that have a title attribute, regardless of which value it has:

p[title] { color:#f00; }

In the following example, the selector matches all div elements that have a class attribute with the value error:

div[class=error] { color:#f00; }

In order to match all td elements whose headers attribute value contains “col1”, the following selector can be used:

td[headers~=col1] { color:#f00; }

And finally, the selector in the following example matches all p elements whose lang attribute starts with en:

p[lang|=en] { color:#f00; }

Multiple attribute selectors can be used in the same selector. This makes it possible to match against several different attributes for the same element. The following rule would apply to all blockquote elements that have a class attribute whose value is exactly “quote”, and a cite attribute (regardless of its value):

blockquote[class=quote][cite] { color:#f00; }

To be continued…

And that brings us to the end of Part 2. In Part 3, the final part in this series, I will explain the pseudo-class and pseudo-element selectors. While you’re waiting for that you may want to revisit Part 1. Repetition is good for learning.

Posted on October 10, 2005 in CSS