The Child Selector

Web Review
June 2000

In the second of five articles on the new selectors found in CSS2, we turn to the child selector. This is used to match elements that are direct children of other elements, which is a little more precise than the traditional contextual selector. If you haven't read the article on the universal selector, though, you may want read it first, since the universal selector appears in some of the examples for this, and future, articles.

How It Works

Using the child selector is pretty easy. It's written using a greater-than symbol (>), and it must appear between two other selectors. For example:

body > p {color: green;}

This rule will make green any paragraph which is a direct child of the body element. Therefore, any paragraph which is the child of some other element-- for example, a div or a table cell-- will not be matched by this rule.

How is this different from traditional contextual selectors? The difference is that, given a selector like bodyp, any paragraph which is a descendant of the body will be matched. That can mean a child paragraph, of course, but it can also mean a paragraph which is contained inside a table cell that's inside a table that's part of a div. Contextual selectors could easily be called descendant selectors, since they define which descendants of which elements can be selected.

Selecting Precise Descendants

By chaining child selectors together, it's possible to very precisely target certain elements at certain points in the document. For example, let's say we want to select any paragraph which is the child of a div, which is itself the child of a div which is the child of the body element. Furthermore, we want to make those paragraphs lime green on a cyan background. Thus we write:

body > div > div > p {color: lime; background: cyan;}

This will work on exactly those paragraphs described above, and no others. If we have a paragraph nested inside three divs, it won't be selected; neither would a paragraph inside a div which is a child of the body element.

Children and Descendants

For those who are confused by the difference between children and descendants, let's explore that for a moment. In order to understand it, though, we need to introduce the concept of a "tree view" for a given document. HTML documents, and indeed most structured documents of any kind, are based on a hierarchy of elements, which is most visible in a tree view of the document. In this hierarchy, each element fits somewhere into the overall structure of the document, and every element is either the parent or child of another element, and often both. See Figure 1 for an example of a document tree.

Element hierarchy diagram.
Figure 1: Element hierarchy diagram.

First, let's talk about the parent-child relationship. In Figure 1, the body element has two children: a p element and a ul element. The p element, in turn, has two children: the em and strong elements directly below it on the tree. The p element has one parent, and that's the body element. In fact, an element can only ever have one parent, although it can have many children.

Now for ancestors and descendants. Take the anchor, a element. It has three ancestors: strong, p, and body. As we walk up the tree toward the top level, every element we pass is an ancestor of the element where we started. Going the other way is more complicated: To find descendants, we have to follow all the branches downward from our starting point. Thus, for the paragraph, p element, the descendants are: em, strong, a, and em.

Thus, in order to select the a element using child selector, we would need to write strong > a. Something else, such as p > a would not match the anchor, because it is not a child of the paragraph.

This is not to say that child selection and descendant selections must remain forever separated, as we'll see in the next section.

Children in Context

In addition to the simple child selections we've seen so far, it's possible to make a child selector part of a contextual selector as well:

div ol > li em {color: purple;}

This rule matches any em text that is a descendant of a list item, as long as that list item is a child of an OL element that is a descendant of a div. Note also that there is no whitespace around the > symbol this time, which is legal: Whitespace around this symbol is optional. Thus:

  <li>The em text here is <em>not</em> purple.</li>
   <li>Look, a list:
     <li>The emphasized text here <em>is</em> purple.</li>

The purple em text is purple because it's the great-grandchild of an li that is the direct child of the ol, and the ol is the grandchild of the body element. The first em is not matched because its grandparent ol is not the direct child of a div.

Even better, you can string more than one child selector together to precisely target a given type of element. Take this, for example:

body > ol > li {color: silver;}

<body> <ol> <li>The text here is silver.</li> </ol> <div> <ul> <li>Look, a list (and this text is not silver, by the way): <ol> <li>The text here is <em>not</em> silver.</li> </ol> </li> </ul> </div> </body>

The first list item in the source is silver because it's the child of an ordered list that is itself the child of a body. The second list item in the source is the child of an unordered list, so it can't match the rule. Finally, the third list item in the source is a child of an ordered list, but the ol element is the child of an li element, so it doesn't match either.

Universal Children

Sounds like the title of a Star Trek episode, doesn't it? In this case, we're talking about using the universal selector in conjunction with the child selector, which can provide some interesting effects.

Let's say you want to boldface only those elements which are children of the body element. That would be done as follows:

body > * {font-weight: bold;}

With this rule, you can easily see which elements are at the "top level" of the document, and which are nested inside other elements. You can extend this approach to select only grandchildren of the body:

body > * > * {font-weight: bold;}

Now only those elements which are one level down from the "top level" will be selected. Of course, this isn't an effect which we will want very often, but we might want to select only those h1 elements which are grandchildren of the body, and so:

body > * > H1 {font-style: italic;}

We could also select any descendant of an element which is the child of an h1 that is the child of a div:

div > h1 > * *

These sorts of selectors aren't always simple to understand at first glance, but with a little practice and some rigorous thinking, they become clear enough.

Browser Support

The child selector is supported in Internet Explorer 5.x for the Macintosh, and Opera 3.6. It is also supported in the Netscape 6 Preview Release 1 for all the myriad platforms for which it's available, and in Preview Release 3 of Opera 4 for Windows.

Still More to Come

As we've seen, the child selector is a very precise operator, but when combined with contextual and universal selectors, it can lead to some surprising possibilities. The sorts of selections possible are far beyond anything which can be achieved with simple contextual selectors alone.

This isn't the end of it, though. As we'll see in the next article in the series, the adjacent-sibling selector makes for even more complicated-- but often vastly more useful-- selectors than those we've already seen.