New Pseudo-Classes

Web Review
July 2000

In our continuing series of articles on the new selectors of CSS2, we've covered the universal, child, and adjacent-sibling selectors. In this article, we present a mixed bag of pseudo-classes, each of which does something very different. Because of this mixture of new features, this article will be a little bit longer than the previous ones, but I promise it will be worth the effort.

Odds are that you're already familiar with CSS pseudo-classes. :link and :visited are two examples of pseudo-classes; they typify the syntax of a pseudo-class, which is a colon (:) followed by the actual identifier. These are typically associated with a document element, but can be combined with classes and IDs as well. For example:

A:link {color: maroon;}
A.external:link {color: green;}
*:visited {color: gray;}

The first of these rules sets the color of any anchor hyperlink pointing to an unvisited URL to maroon. The second rule designates unvisited links with a class of external to be green, and the third sets any element that is a pointer to a visited URL to gray.

Using the pseudo-classes we'll examine here, authors can:

The first feature on the list is similar to other hyperlink-related pseudo-classes, although in theory it isn't constrained to links.

Hover Styles

Introduced by Internet Explorer 4 and incorporated into CSS2, :hover sets the styles for any element that is being "hovered"-- that is, the mouse pointer is positioned over the element itself. The most common use for this pseudo-class is similar to this example:

A:link {color: purple; background: white;}
A:visited {color: gray; background: white;}
A:hover {color: red; background: white;}
hyperlink styles
Figure 1. Visited, unvisited, and hover styles for hyperlinks.

As you can see in Figure 1, the various links are styled appropriately. Notice the link which is red. It's red because the mouse pointer is currently hovering over the link. This is, of course, very similar to the image rollovers so many sites employ. The advantage of :hover is that you don't need Javascript and a bunch of images to make it work.

Another advantage is a little more theoretical, but interesting. CSS2 makes it clear that :hover need not be constrained only to hyperlinks. It should be possible, for example, to use this rule:

P:hover {color: black; background: yellow; border: medium solid orange;}

In this example, any paragraph with the mouse pointer hovering over it would display a yellow background and an orange border. This may seem like useless, annoying eye candy, but consider a situation such as a presentation. Instead of using a laser pointer to highlight given paragraphs, the speaker need only move the mouse pointer until it's over the relevant paragraph, and voila, it's highlighted.

As you know, this is only possible if the user agent supports the application of :hover to elements other than hyperlinks. As of this writing, that describes some builds of Mozilla. The other browsers only support hover styles on hyperlinks.

Even with a browser that fully supports hover styles, one thing you may want to avoid is changing the weight or size of an element when it's being hovered. Consider the implications of this style:

P:hover {font-size: 300%;}

Now any hovered paragraph text will balloon to three times its normal size! But what will happen? Does the entire page get redrawn as a result, or will the text just get huge and overwrite other content? The CSS2 specification clearly states that it's up to user agents to decide, and also that user agents are not required to reflow the document. A browser then might not change the document layout to accommodate the expanded text. But then again, it might.

If a browser does support this, then legalese would become much easier to read. Consider this example: {font-size: 50%;} {font-size: 300%;}

This would make reading the fine print much easier on the eyes. You could also use :hover to make it clear over which form elements the reader's mouse is placed.

INPUT:hover, SELECT:hover, TEXTAREA:hover {background: purple;}

Once you've done that, wouldn't it be cool if you could apply styles to the specific form element with which the user is currently interacting?

Focusing with Style

Thanks to :focus, you can complement the hover styles with focus styles. An element is said to have focus if it allows the user to input data in some way. One example is with forms; whichever input is currently selected has the focus:

INPUT:focus {color: black; background: yellow;}

This rule specifies that wherever the user is typing, or is currently able to type, will have a yellow background with black text. This is demonstrated in Figure 2.

styling with focus
Figure 2. Styling the element with focus.

The same document-reflow issues that came up with :hover also apply to :focus. Consider the potential havoc caused by:

INPUT:focus {font-size: 250%;}

It's hard to say which would be worse: a user agent that did reflow the document in this circumstance, or one that didn't. Either way, since currently very few user agents support this sort of behavior, we'll all have plenty of time to figure out good and bad ways to use :focus.

Language-Dependent Styling

On a rather different note, CSS2 makes it possible to apply styles to elements, or even entire documents, based on the human language being used. Of course, the user agent isn't going to figure that out on its own. It will need a little help from the document itself, such as the value of the lang attribute provided in the HTML. Let's assume a document of mixed English and German text, where each element has a lang attribute to indicate which laguage is in use:

<p lang="en">One two three</p>
<p lang="de">Ein zwei drei</p>

Now we decide that all English elements should be red text on a white background, and all German elements should be black text over a yellow background. The styles we need are:

*:lang(en) {color: red; background: white;}
*:lang(de) {color: black; background: yellow;}

This will yield the results in Figure 3.

language and style
Figure 3. Language and style.

It should also be possible to style entire documents based on their language, assuming that there is some indication of what that is. For example:

HTML:lang(en) {color: red; background: white;}
HTML:lang(de) {color: black; background: yellow;}

If the document's language is given-- through a lang attribute on the HTML element, or as an HTTP header, or even as a META element-- then it would be possible to construct rules to apply to them, as shown above.

Picking the First Child

Finally we come to a pseudo-class a little more in line with the selectors we've seen in the other articles in the series. With :first-child, you can apply styles to the first element contained within another. In order to understand this a little better, we need to return to the tree view of a document.

tree view: first children
Figure 4. Tree view of a document, with first children marked red.

In Figure 4, we've marked the first children red so that they're more obvious. As you can see, any element that is the only child of another element is also the first child. If an element has multiple children, however, then only the first one is selected.

So here's how it works. Let's say you want the first child of any element to be red, as in Figure 4. We'd write it this way:

*:first-child {color: red;}

Simple enough, right? What we have to understand, though, is how this really works. *:first-child indicates that any element that is the first child of another element should be red. This is quite different than saying "the first child of the given element is red," which is not what the :first-child pseudo-class does. Going back to Figure 4, let's say that we only want list items that are first children to be red. No problem. That's written:

LI:first-child {color: red;}

In other words, any LI list element that is the first child of another element should be red. Now, let's assume that we change that to the selector UL:first-child. In that case, only the lower UL in Figure 4 (the red one) would be selected, as it's the first (and only) child of an LI element. The "higher" UL in Figure 4 is the second child of the BODY element, so it wouldn't be selected.

It's also important to realize how this pseudo-class operates in contextual selectors, and ,indeed, in conjunction with any other selector. Let's say we want the first child of the BODY to be italicized. The correct way to select for it would be:

BODY > *:first-child {font-style: italic;}

The addition of the child selector (>) is what makes this work, as it italicizes any element that is the first child of the BODY. Assume if we leave out the child selector, we'd end up with:

BODY *:first-child {font-style: italic;}

In this case, any element that is the first child of another element, and is the descendant of the BODY element, should be italicized. We could have just left out the BODY part of the selector, and the effect would be the same, assuming the document is valid HTML, of course.

That's not to say that you can never use :first-child in a descendant selector. You might want to boldface the first list item of any list contained within any unordered list:

UL LI:first-child {font-weight: bolder;}

Now any list item that is a first child, and that is some descendant of an unordered list, will be boldfaced. This is true even if the LI is a child of an ordered list, so long as one of its ancestors is a UL element. See Figure 5 for an example.

selecting the first child list elements
Figure 5. Selecting the first-child LI elements that descend from a UL element.

By combining the first-child pseudo-class with the adjacent-sibling selector, it's possible to pick children other than the first one. For example, you might want to always style the third child of any element. That could be accomplished by writing:

*:first-child + * + * {color: green;}

It isn't necessarily the most common thing you'll ever try to do, but you never know. Just as an example, you might want to make the first list-item in a list boldfaced and red, the second boldfaced, and the third one gray. The styles would be:

LI:first-child {font-weight: bold; color: red;}
LI:first-child + LI {font-weight: bold;}
LI:first-child + LI + LI {color: gray;}

Again, it probably isn't something you've been waiting years to be able to accomplish, but now the capability is there for those moments when you need it.

End Results

No matter which of these pseudo-classes you find most interesting-- most people leap at the ability to use :hover, while :first-child is potentially much more useful-- the letdown is in browser support. A quick glance at the entries on the SS2 Selectors Chart shows the lack of support for these features among legacy browsers, although among recent releases there are signs of hope. Not reflected on this chart is Mozilla, which generally does support all of the features covered in this article. Due to the unstable nature of Mozilla at this time, however, it's difficult to say that full support is there or not there-- which is why it isn't on the chart.

For those who are planning ahead, the next (and last) installment in the series will actually be a three-part piece that covers attribute selectors, which in many ways are the most powerful addition to CSS selectors. You may also want to be on the lookout for an upcoming article that explains how to use CSS pseudo-elements and classes most effectively, and how they've changed a bit from the old CSS1 rules. Until then, have fun experimenting with the things we've discussed so far!