home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Book HomeCascading Style Sheets: The Definitive GuideSearch this book

10.2. CSS2 Selectors

We're going to discuss CSS2 selectors in some detail because they're likely to be one of the first parts of the specification to be implemented quickly. Therefore, while you might not be able to do everything described here as soon as you read this, expect most (if not all) of this to be included in browsers released in the year 2000 or later.

10.2.1. Basic Selectors

First, in addition to the existing selector mechanisms like contextual selectors, we have several new selector symbols that will make it a lot easier to construct very specific, very sophisticated selections -- without having to resort to sprinkling classes or IDs throughout the whole document.

10.2.1.1. Universal selector

The most powerful of the new selectors is the universal selector. This is specified using an asterisk (*), and it matches any element in the document. Thus, use this declaration to make sure all elements have a color of black:

* {color: black;}

When used as part of a contextual selector, the universal selector can create some interesting effects. For example, assume that you want to make gray any UL element that is at least a grandchild of the BODY. In other words, any UL that is a child of BODY would not be gray, but any other UL -- whether it's child to a DIV, a list item, or a table -- should be gray. This is accomplished as follows:

BODY * UL {color: gray;}

Figure 10-3 shows the result of this declaration.

Figure 10-3

Figure 10-3. Making BODY's grandchildren (and their descendants) gray

On the other hand, perhaps you wish to make purple any element that is a descendant of DIV. This would be written:

DIV * {color: purple;}

At first glance, this seems no different than if the * were left out, instead relying on inheritance to carry the color to all descendants of DIV. However, there is a very real difference: the rule shown would match every DIV descendant, and therefore override the inheritance mechanism. Thus, even anchors (which are descendants of a DIV) would be made purple under the given rule, whereas simple inheritance would not be sufficient to make them purple.

While you can use the universal selector in combination with class and ID selectors, there isn't much reason to do so. The following two rules mean exactly the same thing:

*.apple {color: red;}
.apple {color: red;}

However, you should consider this: if you're concerned about older user agents that don't know about CSS2, then *.class (or *#id) is an easy way to fool them. Since both of these are examples of invalid selectors in CSS1, they should be ignored by CSS1-only parsers. If they aren't ignored, then they're likely to cause strange results. Therefore, it might be a good idea to omit the universal selector in conjunction with class and ID selectors.

10.2.1.2. Child selector

Another interesting selector is the child selector, which is written using a greater-than symbol (>). This is used to match elements that are direct children of other elements:

BODY > P {color: green;}

<BODY>
<P>This paragraph is green.</P>
<DIV>
<P>This paragraph is not green.</P>
</DIV>
<P>This paragraph is green.</P>
</BODY>

Only the first and third paragraphs match the rule because they are children of BODY. The second paragraph is a child of DIV, and therefore a grandchild of BODY, so it does not match the rule.

Child selectors must have at least two or more selectors separated by the > symbol. It is 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:

<BODY>
<OL>
<LI>The EM text here is <EM>not</EM> purple.</LI>
</OL>
<DIV>
<OL>
<LI>Look, a list:
<UL>
<LI>The emphasized text here <EM>is</EM> purple.</LI>
</UL>
</LI>
</OL>
</DIV>
</BODY>

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>

Given this rule, we get results like those shown in Figure 10-4.

Figure 10-4

Figure 10-4. Selecting grandchildren only

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.

10.2.1.3. Adjacent-sibling selector

If you thought that was interesting, consider our next subject: the adjacent sibling selector. This is in some ways like the child selector, but in this case, styles are applied to elements that share a parent and are next to each other in the document tree. For example:

H2 + P {color: silver;}

<H2>Coloring Text</H2>
<P>This paragraph is silver.</P>
<P>This paragraph is not.</P>

<H2>More Coloring Text</H2>
<UL><LI>This is not silver</LI></UL>
<P>Neither is this.</P>

<H2>More Coloring Text</H2>
This text is not silver.
<P>This paragraph is silver.</P>
<P>This paragraph is not.</P>

In the first set of markup, a paragraph immediately follows an H2, so it is silver. In the second, the element adjacent to the H2 is a UL, which does not match the rule, and neither does the paragraph right after that. Finally, even though there is text directly after the third H2, it isn't part of an element, so the paragraph right after the text matches the rule and is colored silver. All this is demonstrated in Figure 10-5.

Figure 10-5

Figure 10-5. Selecting adjacent elements

If you wanted to make any element immediately following an H2 silver, then the universal selector comes into play:

H2 + * {color: silver;}

The fact that user agents ignore text between elements can actually be used to your advantage in many circumstances. Take, for example, a document design in which you want STRONG text to be gray, except when it follows EM text, in which case it should be silver:

STRONG {color: gray;}
EM + STRONG {color: silver;}

<P>While the first strong element is <STRONG>gray</STRONG>, the 
<EM>second</EM> strong element is <STRONG>silver</STRONG>, because it
follows an "EM" element.

The result is shown in Figure 10-6.

Figure 10-6

Figure 10-6. More adjacent selections

10.2.2. Attribute Selectors

With the introduction of attribute selectors , CSS gains a great deal of flexibility, precision, and power. Attribute selectors can be matched in four ways, each of which carries its own strengths and advantages.

10.2.2.3. Matching single attribute values

It has been possible since HTML 3.2 to set multiple class names on a given element, such as:

<P CLASS="footnote example reference">

In CSS1 you could only refer to one of the values, using a selector like P.example. In CSS2, you can create a selector such that the class name must be an exact match, or you can set it up so that only one of the values has to match. P[class="example"] wouldn't match the preceding three-class paragraph, because the values are different (example isn't the same as footnote example reference).

On the other hand, P[class~="example"] would match footnote example reference because this type of selector has only to match oneof the values in the class attribute. The only difference is the tilde character (~), but what a difference!

As an example, let's assume a document in which elements can have one or more class values of driving, flying, nautical, directions, and title. Thus, an element could have a class of driving directions, or perhaps flying directions title. Furthermore, we decide that while all titles should be red, anything (other than a title) relating to flying should be green and anything relating to driving should be purple. These can be declared as follows:

*[class~="flying"] {color: green;}
*[class~="driving"] {color: purple;}
*[class~="title"] {color: red;}

The tilde (~) before the equals sign is what causes these selectors to match any one of the values in the class attribute. Thus, the following rule would match any IMG element with a class of figure and an alt attribute that contains the word Figure -- such as Figure 1, Figure 2, and so on:

IMG[class="figure"][alt~="Figure"] {margin: 5px;}

<IMG SRC="picture13.jpg" CLASS="figure" ALT="Figure 13">

10.2.2.4. Simulating class and ID

Using attribute selectors, you can also simulate class and ID selectors. The following pairs of rules are roughly equivalent:

P[class="directions"] {color: red;}
P.directions {color: red;}

DIV[ID="abc123"] {color: blue;}
DIV#abc123 {color: blue;}

Obviously, the latter rule in each pair is much simpler to type and edit, and you'll probably use such rules in most circumstances.

If you want an exact match, you can use an ordinary attribute selector. Thus, the following rule:

P[class="driving directions"] {color: green;}

will match this markup:

<P CLASS="driving directions" >This is a side note (and it's green).</P>

If you aren't quite so concerned about exact matching, you can string class selectors together. This is a new feature of CSS2, and with this approach, you can match a class attribute with a value of driving directions in this way:

P.driving.directions {color: blue;}

<P CLASS="driving directions">This is a side note (and it's blue this time).
</P>

You could use the same selector to match the value directions for driving, since it contains both driving and directions -- just not in that order.

Again, this probably seems a bit easier to type. So why go to all the effort of using the longer notation of attribute selectors? The reason to use attribute selectors is that the .class and #ID selectors apply only to HTML documents, or to any other document that uses a language that includes the concepts of class and ID. Other languages, such as those based on XML, might not honor these conventions, in which case you'll need to use the attribute selectors instead.

10.2.3. More Pseudo-Classes and Pseudo-Elements

Even though that might seem like it's more than enough, another area of expansion is in pseudo-class and pseudo-element selectors.

10.2.3.1. :hover

To begin, there is :hover. The basic idea is that the styles in a :hover rule are applied while your mouse pointer is "hovering" over an element. For example, when the pointer is positioned over a link such that clicking the mouse button would cause the browser to follow the link, the pointer is "hovering" over the link. This is in some respects similar to the somewhat famous JavaScript "rollover" trick, where images change when the pointer hovers over them. Thanks to :hover, you can specify a hover style very easily:

A:link {background: white; color: blue;}
A:hover {background: blue; color: white;}

These styles will cause anchors to "reverse" in color when the mouse pointer hovers over them, as illustrated in Figure 10-9.

Figure 10-9

Figure 10-9. Hover styles

As a matter of fact, the rule for A:hover would be used while the pointer hovers over any anchor, not just a hyperlink. While some other pseudo-classes, like :link and :visited , are constrained to the A element in HTML, the same is not true of :hover. User agents could, in theory, allow the assignment of hover styles to any element, like this:

P:hover {font-weight: bold;}

Therefore, if you want to make sure your hover styles are applied only to your hyperlinks, you would need to use this rule:

A:link:hover {background: blue; color: white;}

The ability to combine pseudo-classes is a new feature of CSS2.

WARNING

Internet Explorer 4.x and 5.x both recognize :hover on anchors only. As of this writing, no other browser will recognize :hover under any circumstances.

10.2.3.4. :first-child

The last of the new pseudo-class selectors we'll cover here is the :first-child selector. This is used to match an element that is the first child of another element. For example, you might want to make the first child of every DIV italicized instead of normal text, as long as that first child is a paragraph (shown in Figure 10-11):

P {color: black;}
P:first-child {font-style: italic;}

<BODY>
<P>This paragraph should be italic.</P>
<P>This paragraph should be normal.</P>
<DIV STYLE="border: 1px dashed gray;">
This text should be normal.
<P>This paragraph should be italic.</P>
<P>This paragraph should be normal.</P>
</DIV>
<DIV STYLE="border: 1px dotted gray;">
<H2>This H2 should be normal.</H2>
<P>This paragraph should be normal.</P>
<P>This paragraph should be normal.</P>
</DIV>
</BODY>
Figure 10-11

Figure 10-11. Selecting styles for certain first children

The very first paragraph is italicized because it is the first child of the BODY element. Similarly, the first paragraph in the first DIV is italicized because it is the first child of the DIV, even though text preceded it. Only structural elements count for this pseudo-class, so the text before the paragraph doesn't affect the paragraph's status as the first child. However, in the second DIV, the H2 is the first child, so it does not match the rule P:first-child. If the intent is to have the first child of any element be italicized, no matter what element that might be, then you need only leave off the element part of the selector, or use it in conjunction with the universal selector. This will yield the result shown in Figure 10-12:

*:first-child {font-style: italic;}
Figure 10-12

Figure 10-12. Selecting any first child

Now let's say we want to apply styles to elements that are part of a first child; for example, all emphasized text within a first-child paragraph should be italicized:

P:first-child EM {font-style: italic;}

Of course, this will match any first-child paragraph, no matter its parent element. Suppose instead we want a rule that applies only to paragraphs that are the first children of DIV elements. In that case, we need to use the child selector:

DIV > P:first-child {font-style: italic;}

This translates as, "any paragraph that is a first child, and is a child of a DIV, should be in italics." If we were to leave out the child selector as follows, though:

DIV P:first-child {font-style: italic;}

then the rule would read, "any paragraph that is a first child of any element, and is also a descendant of a DIV, should be in italics." The difference is subtle, but real.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.