One of the primary advantages of CSS is its ability to easily apply a set of styles to all elements of the same type. Unimpressed? Consider this: by editing a single line of CSS, you can change the colors of all your headings. Don’t like the blue you’re using? Change that one line of code, and they can all be purple, yellow, maroon, or any other color you desire. That lets you, the designer, focus on design, rather than grunt work. The next time you’re in a meeting and someone wants to see headings with a different shade of green, just edit your style and hit Reload. Voilà! The results are accomplished in seconds and there for everyone to see.
As stated, a central feature of CSS is its ability to apply certain rules to an entire set of element types in a document. For example, let’s say that you want to make the text of all h2
elements appear gray. Using old-school HTML, you’d have to do this by inserting <font color="gray">…</font>
tags inside all your h2
elements. Using the style
attribute, which is also bad practice, would require you to include style="color: gray;"
in all your h2
elements, like this:
<h2><font
color=
"gray"
>
This is h2 text</font></h2>
<h2
style=
"color: gray;"
>
This is h2 text</h2>
This will be a tedious process if your document contains a lot of h2
elements. Worse, if you later decide that you want all those h2
s to be green instead of gray, you’d have to start the manual tagging all over again. (Yes, this is really how it used to be done!)
CSS allows you to create rules that are simple to change, edit, and apply to all the text elements you define (the next section will explain how these rules work). For example, you can write this rule once to make all your h2
elements gray:
h2
{
color
:
gray
;}
If you want to change all h2
text to another color—say, silver—just alter the value:
h2
{
color
:
silver
;}
An element selector is most often an HTML element, but not always. For example, if a CSS file contains styles for an XML document, the element selectors might look something like this:
quote
{
color
:
gray
;}
bib
{
color
:
red
;}
booktitle
{
color
:
purple
;}
myElement
{
color
:
red
;}
In other words, the elements of the document serve as the most basic selectors. In XML, a selector could be anything, since XML allows for the creation of new markup languages that can have just about anything as an element name. If you’re styling an HTML document, on the other hand, the selector will generally be one of the many HTML elements such as p
, h3
, em
, a
, or even html
itself. For example:
html
{
color
:
black
;}
h1
{
color
:
gray
;}
h2
{
color
:
silver
;}
The results of this stylesheet are shown in Figure 2-1.
Once you’ve globally applied styles directly to elements, you can shift those styles from one element to another. Let’s say you decide that the paragraph text, not the h1
elements, in Figure 2-1 should be gray. No problem. Just change the h1
selector to p
:
html
{
color
:
black
;}
p
{
color
:
gray
;}
h2
{
color
:
silver
;}
The results are shown in Figure 2-2.
The declaration block contains one or more declarations. A declaration is always formatted as a property followed by a colon and then a value followed by a semicolon. The colon and semicolon can be followed by zero or more spaces. In nearly all cases, a value is either a single keyword or a space-separated list of one or more keywords that are permitted for that property. If you use an incorrect property or value in a declaration, the whole rule will be ignored. Thus, the following two declarations would fail:
brain
-
size
:
2cm
;
/* unknown property 'brain-size' */
color
:
ultraviolet
;
/* unknown value 'ultraviolet' */
In an instance where you can use more than one keyword for a property’s value, the keywords are usually separated by spaces, with some cases requiring slashes (/) or commas. Not every property can accept multiple keywords, but many, such as the font
property, can. Let’s say you want to define medium-sized Helvetica for paragraph text, as illustrated in Figure 2-3.
The rule would read as follows:
p
{
font
:
medium
Helvetica
;}
Note the space between medium
and Helvetica
, each of which is a keyword (the first is the font’s size and the second is the actual font name). The space allows the user agent to distinguish between the two keywords and apply them correctly. The semicolon indicates that the declaration has been concluded.
These space-separated words are referred to as keywords because, taken together, they form the value of the property in question. For instance, consider the following fictional rule:
rainbow: red orange yellow green blue indigo violet;
There is no such property as rainbow
, but the example is useful for illustrative purposes. The value of rainbow
is red orange
yellow green blue indigo violet
, and the seven keywords add up to a single, unique value. We can redefine the value for rainbow
as follows:
rainbow: infrared red orange yellow green blue indigo violet ultraviolet;
Now we have a new value for rainbow
composed of nine keywords instead of seven. Although the two values look mostly the same, they are as unique and different as zero and one. This may seem an abstract point, but it’s critical to understanding some of the subtler effects of specificity and the cascade (covered later in this book).
As we’ve seen, CSS keywords are usually separated by spaces. In CSS2.1 there was one exception: in the CSS property font
, there is exactly one place where a forward slash (/
) could be used to separate two specific keywords. Here’s an example:
h2
{
font
:
large
/
150%
sans-serif
;}
The slash separates the keywords that set the element’s font size and line height. This is the only place the slash is allowed to appear in the font
declaration. All of the other keywords allowed for font
are separated by spaces.
The slash has since worked its way into a number of other properties’ values. These include, but may not always be limited to the following:
background
border-image
border-radius
grid
grid-area
grid-column
grid-row
grid-template
mask-border
There are also some keywords that are separated by commas. When declaring multiple values, such as multiple background images, transition properties, and shadows, the declarations are separated with commas. Additionally, parameters in functions, such as linear gradients and transforms, are comma separated, as the following example shows:
.box
{
box-shadow
:
inset
-1px
-1px
white
,
3px
3px
3px
rgba
(
0
,
0
,
0
,
0
.
2
);
background-image
:
url(myimage.png)
,
linear
-
gradient
(
180deg
,
#FFF
0%
,
#000
100%
);
transform
:
translate
(
100px
,
200px
);
}
a
:hover
{
transition
:
color
,
background
-
color
200ms
ease
-
in
50ms
;}
Those are the basics of simple declarations, but they can get much more complex. The next section begins to show you just how powerful CSS can be.
So far, we’ve seen fairly simple techniques for applying a single style to a single selector. But what if you want the same style to apply to multiple elements? If that’s the case, you’ll want to use more than one selector or apply more than one style to an element or group of elements.
Let’s say you want both h2
elements and paragraphs to have gray text. The easiest way to accomplish this is to use the following declaration:
h2
,
p
{
color
:
gray
;}
By placing the h2
and p
selectors on the left side of the rule and separating them with a comma, you’ve defined a rule where the style on the right (color
: gray;
) applies to the elements referenced by both selectors. The comma tells the browser that there are two different selectors involved in the rule. Leaving out the comma would give the rule a completely different meaning, which we’ll explore in “Descendant Selectors”.
There are really no limits to how many selectors you can group together. For example, if you want to display a large number of elements in gray, you might use something like the following rule:
body
,
table
,
th
,
td
,
h1
,
h2
,
h3
,
h4
,
p
,
pre
,
strong
,
em
,
b
,
i
{
color
:
gray
;}
Grouping allows an author to drastically compact certain types of style assignments, which makes for a shorter stylesheet. The following alternatives produce exactly the same result, but it’s pretty obvious which one is easier to type:
h1
{
color
:
purple
;}
h2
{
color
:
purple
;}
h3
{
color
:
purple
;}
h4
{
color
:
purple
;}
h5
{
color
:
purple
;}
h6
{
color
:
purple
;}
h1
,
h2
,
h3
,
h4
,
h5
,
h6
{
color
:
purple
;}
Grouping allows for some interesting choices. For example, all of the groups of rules in the following example are equivalent—each merely shows a different way of grouping both selectors and declarations:
/* group 1 */
h1
{
color
:
silver
;
background
:
white
;}
h2
{
color
:
silver
;
background
:
gray
;}
h3
{
color
:
white
;
background
:
gray
;}
h4
{
color
:
silver
;
background
:
white
;}
b
{
color
:
gray
;
background
:
white
;}
/* group 2 */
h1
,
h2
,
h4
{
color
:
silver
;}
h2
,
h3
{
background
:
gray
;}
h1
,
h4
,
b
{
background
:
white
;}
h3
{
color
:
white
;}
b
{
color
:
gray
;}
/* group 3 */
h1
,
h4
{
color
:
silver
;
background
:
white
;}
h2
{
color
:
silver
;}
h3
{
color
:
white
;}
h2
,
h3
{
background
:
gray
;}
b
{
color
:
gray
;
background
:
white
;}
Any of these will yield the result shown in Figure 2-4. (These styles use grouped declarations, which are explained in “Grouping Declarations”.)
CSS2 introduced a new simple selector called the universal selector, displayed as an asterisk (*
). This selector matches any element at all, much like a wildcard. For example, to make every single element in a document red, you would write:
*
{
color
:
red
;}
This declaration is equivalent to a grouped selector that lists every single element contained within the document. The universal selector lets you assign the color
value red
to every element in the document in one efficient stroke. Beware, however: although the universal selector is convenient, because it targets everything within its declaration scope, it can have unintended consequences, which are discussed later in this book.
Since you can group selectors together into a single rule, it follows that you can also group declarations. Assuming that you want all h1
elements to appear in purple, 18-pixel-high Helvetica text on an aqua background (and you don’t mind blinding your readers), you could write your styles like this:
h1
{
font
:
18px
Helvetica
;}
h1
{
color
:
purple
;}
h1
{
background
:
aqua
;}
But this method is inefficient—imagine creating such a list for an element that will carry 10 or 15 styles! Instead, you can group your declarations together:
h1
{
font
:
18px
Helvetica
;
color
:
purple
;
background
:
aqua
;}
This will have exactly the same effect as the three-line stylesheet just shown.
Note that using semicolons at the end of each declaration is crucial when you’re grouping them. Browsers ignore whitespace in stylesheets, so the user agent must rely on correct syntax to parse the stylesheet. You can fearlessly format styles like the following:
h1
{
font
:
18px
Helvetica
;
color
:
purple
;
background
:
aqua
;
}
You can also minimize your CSS, removing all non-required spaces.
h1
{
font
:
18px
Helvetica
;
color
:
purple
;
background
:
aqua
;}
Ignoring whitespace, the last three are treated equally by the server, but the second one is most human readable, and the recommended method of marking up your CSS during development. (You might choose to minimize your CSS for network-performance reasons, but this is usually handled by a server-side script, caching network, or other service.)
If the semicolon is omitted on the second statement, the user agent will interpret the stylesheet as follows:
h1
{
font
:
18px
Helvetica
;
color
:
purple
background
:
aqua
;
}
Because background:
is not a valid value for color
, and because color
can be given only one keyword, a user agent will ignore the color
declaration (including the background: aqua
part) entirely. You might think the browser would at least render h1
s as purple text without an aqua background, but not so. Instead, they will be the default color (which is usually black) with a transparent background (which is also a default). The declaration font: 18px Helvetica
will still take effect since it was correctly terminated with a semicolon.
Although it is not technically necessary to follow the last declaration of a rule with a semicolon in CSS, it is generally good practice to do so. First, it will keep you in the habit of terminating your declarations with semicolons, the lack of which is one of the most common causes of rendering errors. Second, if you decide to add another declaration to a rule, you won’t have to worry about forgetting to insert an extra semicolon. Third, if you ever use a preprocessor like Sass, trailing semicolons are often required for all declarations. Avoid all these problems—always follow a declaration with a semicolon, wherever the rule appears.
As with selector grouping, declaration grouping is a convenient way to keep your stylesheets short, expressive, and easy to maintain.
You now know that you can group selectors and you can group declarations. By combining both kinds of grouping in single rules, you can define very complex styles using only a few statements. Now, what if you want to assign some complex styles to all the headings in a document, and you want the same styles to be applied to all of them? Here’s how to do it:
h1
,
h2
,
h3
,
h4
,
h5
,
h6
{
color
:
gray
;
background
:
white
;
padding
:
0.5em
;
border
:
1px
solid
black
;
font-family
:
Charcoal
,
sans-serif
;}
Here we’ve grouped the selectors, so the styles on the right side of the rule will be applied to all the headings listed; grouping the declarations means that all of the listed styles will be applied to the selectors on the left side of the rule. The result of this rule is shown in Figure 2-5.
This approach is preferable to the drawn-out alternative, which would begin with something like this:
h1
{
color
:
gray
;}
h2
{
color
:
gray
;}
h3
{
color
:
gray
;}
h4
{
color
:
gray
;}
h5
{
color
:
gray
;}
h6
{
color
:
gray
;}
h1
{
background
:
white
;}
h2
{
background
:
white
;}
h3
{
background
:
white
;}
and continue for many lines. You can write out your styles the long way, but I wouldn’t recommend it—editing them would be as tedious as using style
attributes everywhere!
It’s possible to add even more expression to selectors and to apply styles in a way that cuts across elements in favor of types of information. To get something so powerful, you’ll have to do a little work in return, but it’s well worth it.
With updates to HTML, such as the HTML5 specification, new elements have come into being. Some browsers predate these newer elements, and so don’t recognize them. Versions of Internet Explorer prior to IE9, for example, did not support selecting elements they did not understand. The solution was to create the element in the DOM, thereby informing the browser that said element exists.
For example, IE8 does not recognize the <main>
element. The following JavaScript line informs IE8 of main
’s existence:
document
.
createElement
(
'main'
);
By running that line of code, older versions of Internet Explorer will recognize the existence of the element, allowing it to be selected and styled.
So far, we’ve been grouping selectors and declarations together in a variety of ways, but the selectors we’ve been using are very simple ones that refer only to document elements. Element selectors are fine up to a point, but there are times when you need something a little more specialized.
In addition to raw document elements, there are class selectors and ID selectors, which let you assign styles in a way that is independent of document elements. These selectors can be used on their own or in conjunction with element selectors. However, they work only if you’ve marked up your document appropriately, so using them generally involves a little forethought and planning.
For example, say a document contains a number of warnings. You want each warning to appear in boldface text so that it will stand out. However, you don’t know which elements these warnings will be. Some warnings could be entire paragraphs, while others could be a single item within a lengthy list or a small section of text. So, you can’t define a rule using element selectors of any kind. Suppose you tried this route:
p
{
font-weight
:
bold
;
color
:
red
;
}
All paragraphs would be red and bold, not just those that contain warnings. You need a way to select only the text that contains warnings, or more precisely, a way to select only those elements that are warnings. How do you do it? You apply styles to parts of the document that have been marked in a certain way, independent of the elements involved, by using class selectors.
The most common way to apply styles without worrying about the elements involved is to use class selectors. Before you can use them, however, you need to modify your actual document markup so that the class selectors will work. Enter the class
attribute:
<p
class=
"warning"
>
When handling plutonium, care must be taken to avoid the formation of a critical mass.</p>
<p>
With plutonium,<span
class=
"warning"
>
the possibility of implosion is very real, and must be avoided at all costs</span>
. This can be accomplished by keeping the various masses separate.</p>
To associate the styles of a class selector with an element, you must assign a class
attribute the appropriate value. In the previous code block, a class
value of warning
was assigned to two elements: the first paragraph and the span
element in the second paragraph.
All you need now is a way to apply styles to these classed elements. In HTML documents, you can use a compact notation where the name of a class
is preceded by a period (.
) and can be joined with an element selector:
.warning
{
font-weight
:
bold
;}
When combined with the example markup shown earlier, this simple rule has the effect shown in Figure 2-6. That is, the declaration font-weight: bold
will be applied to every element (thanks to the presence of the implicit universal selector) that carries a class
attribute with a value of warning
.
The universal selector, represented by *
, is implied when an ID, class, attribute selector, pseudo-class or pseudo-element selector is written without being attached to an element selector.
As you can see, the class selector works by directly referencing a value that will be found in the class
attribute of an element. This reference is always preceded by a period (.
), which marks it as a class selector. The period helps keep the class selector separate from anything with which it might be combined—such as an element selector. For example, you may want boldface text only when an entire paragraph is a warning:
p
.warning
{
font-weight
:
bold
;}
The selector now matches any p
elements that have a class
attribute containing the word warning
, but no other elements of any kind, classed or otherwise. Since the span
element is not a paragraph, the rule’s selector doesn’t match it, and it won’t be displayed using boldfaced text.
If you did want to assign different styles to the span
element, you could use the selector span.warning
:
p
.warning
{
font-weight
:
bold
;}
span
.warning
{
font-style
:
italic
;}
In this case, the warning paragraph is boldfaced, while the warning span
is italicized. Each rule applies only to a specific type of element/class combination, so it does not leak over to other elements.
Another option is to use a combination of a general class selector and an element-specific class selector to make the styles even more useful, as in the following markup:
.warning
{
font-style
:
italic
;}
span
.warning
{
font-weight
:
bold
;}
The results are shown in Figure 2-7.
In this situation, any warning text will be italicized, but only the text within a span
element with a class
of warning
will be both boldfaced and italicized.
Notice the format of the general class selector in the previous example: it’s a class name preceded by a period without any element name, and no universal selector. In cases where you only want to select all elements that share a class name, you can omit the universal selector from a class selector without any ill effects.
In the previous section, we dealt with class
values that contained a single word. In HTML, it’s possible to have a space-separated list of words in a single class
value. For example, if you want to mark a particular element as being both urgent and a warning, you could write:
<p
class=
"urgent warning"
>
When handling plutonium, care must be taken to avoid the formation of a critical mass.</p>
<p>
With plutonium,<span
class=
"warning"
>
the possibility of implosion is very real, and must be avoided at all costs</span>
. This can be accomplished by keeping the various masses separate.</p>
The order of the words doesn’t matter; warning urgent
would also suffice and would yield precisely the same results no matter how the CSS class
attribute is written.
Now let’s say you want all elements with a class
of warning
to be boldfaced, those with a class
of urgent
to be italic, and those elements with both values to have a silver background. This would be written as follows:
.warning
{
font-weight
:
bold
;}
.urgent
{
font-style
:
italic
;}
.warning.urgent
{
background
:
silver
;}
By chaining two class selectors together, you can select only those elements that have both class names, in any order. As you can see, the HTML source contains class="urgent
warning"
but the CSS selector is written .warning.urgent
. Regardless, the rule will still cause the “When handling plutonium . . . ” paragraph to have a silver background, as illustrated in Figure 2-8. This happens because the order the words are written in doesn’t matter. (This is not to say the order of classes is always irrelevant, but we’ll get to that later in the book.)
If a multiple class selector contains a name that is not in the space-separated list, then the match will fail. Consider the following rule:
p
.warning.help
{
background
:
red
;}
As you would expect, the selector will match only those p
elements with a class
containing the words warning
and help
. Therefore, it will not match a p
element with just the words warning
and urgent
in its class
attribute. It would, however, match the following:
<p
class=
"urgent warning help"
>
Help me!</p>
In some ways, ID selectors are similar to class selectors, but there are a few crucial differences. First, ID selectors are preceded by an octothorpe (#
)—also known as a pound sign (in the US), hash sign, hash mark, or tic-tac-toe board—instead of a period. Thus, you might see a rule like this one:
*
#first-para
{
font-weight
:
bold
;}
This rule produces boldfaced text in any element whose id
attribute has a value of first-para
.
The second difference is that instead of referencing values of the class
attribute, ID selectors refer, unsurprisingly, to values found in id
attributes. Here’s an example of an ID selector in action:
*
#lead-para
{
font-weight
:
bold
;}
<p
id=
"lead-para"
>
This paragraph will be boldfaced.</p>
<p>
This paragraph will NOT be bold.</p>
Note that the value lead-para
could have been assigned to any element within the document. In this particular case, it is applied to the first paragraph, but we could have applied it just as easily to the second or third paragraph. Or an unordered list. Or anything.
As with class selectors, it is possible to omit the universal selector from an ID selector. In the previous example, we could also have written:
#lead-para
{
font-weight
:
bold
;}
The effect of this selector would be the same.
Another similarity between classes and IDs is that IDs can be selected independently of an element. There may be circumstances in which you know that a certain ID value will appear in a document, but you don’t know the element on which it will appear (as in the plutonium-handling warnings), so you’ll want to declare standalone ID selectors. For example, you may know that in any given document, there will be an element with an ID value of mostImportant
. You don’t know whether that most important thing will be a paragraph, a short phrase, a list item, or a section heading. You know only that it will exist in each document, occur in an arbitrary element, and appear no more than once. In that case, you would write a rule like this:
#mostImportant
{
color
:
red
;
background
:
yellow
;}
This rule would match any of the following elements (which, as noted before, should not appear together in the same document because they all have the same ID value):
<h1
id=
"mostImportant"
>
This is important!</h1>
<em
id=
"mostImportant"
>
This is important!</em>
<ul
id=
"mostImportant"
>
This is important!</ul>
You may assign classes to any number of elements, as demonstrated earlier; the class name warning
was applied to both a p
and a span
element, and it could have been applied to many more elements. IDs, on the other hand, should be used once, and only once, within an HTML document. Therefore, if you have an element with an id
value of lead-para
, no other element in that document should have an id
value of lead-para
.
In the real world, browsers don’t always check for the uniqueness of IDs in HTML. That means that if you sprinkle an HTML document with several elements, all of which have the same value for their ID attributes, you’ll probably get the same styles applied to each. This is incorrect behavior, but it happens anyway. Having more than one of the same ID value in a document also makes DOM scripting more difficult, since functions like getElementById()
depend on there being one, and only one, element with a given ID value.
Unlike class selectors, ID selectors can’t be combined with other IDs, since ID attributes do not permit a space-separated list of words.
Another difference between class
and id
names is that IDs carry more weight when you’re trying to determine which styles should be applied to a given element. This will be explained in greater detail in the next chapter.
Also note that class and ID selectors may be case-sensitive, depending on the document language. HTML defines class and ID values to be case-sensitive, so the capitalization of your class and ID values must match that found in your documents. Thus, in the following pairing of CSS and HTML, the element’s text will not be boldfaced:
p
.criticalInfo
{
font-weight
:
bold
;}
<p
class=
"criticalinfo"
>
Don't look down.</p>
Because of the change in case for the letter i, the selector will not match the element shown.
On a purely syntactical level, the dot-class notation (e.g., .warning
) is not guaranteed to work for XML documents. As of this writing, the dot-class notation works in HTML, SVG, and MathML, and it may well be permitted in future languages, but it’s up to each language’s specification to decide that. The hash-ID notation (e.g., #lead
) will work in any document language that has an attribute that enforces uniqueness within a document. Uniqueness can be enforced with an attribute called id
, or indeed anything else, as long as the attribute’s contents are defined to be unique within the document.
When it comes to both class and ID selectors, what you’re really doing is selecting values of attributes. The syntax used in the previous two sections is particular to HTML, XHTML, SVG, and MathML documents (as of this writing). In other markup languages, these class and ID selectors may not be available (as, indeed, those attributes may not be present). To address this situation, CSS2 introduced attribute selectors, which can be used to select elements based on their attributes and the values of those attributes. There are four general types of attribute selectors: simple attribute selectors, exact attribute value selectors, partial-match attribute value selectors, and leading-value attribute selectors.
If you want to select elements that have a certain attribute, regardless of that attribute’s value, you can use a simple attribute selector. For example, to select all h1
elements that have a class
attribute with any value and make their text silver, write:
h1
[
class
]
{
color
:
silver
;}
So, given the following markup:
<h1
class=
"hoopla"
>
Hello</h1>
<h1>
Serenity</h1>
<h1
class=
"fancy"
>
Fooling</h1>
you get the result shown in Figure 2-9.
This strategy is very useful in XML documents, as XML languages tend to have element and attribute names that are specific to their purpose. Consider an XML language that is used to describe planets of the solar system (we’ll call it PlanetML). If you want to select all pml-planet
elements with a moons
attribute and make them boldface, thus calling attention to any planet that has moons, you would write:
pml-planet
[
moons
]
{
font-weight
:
bold
;}
This would cause the text of the second and third elements in the following markup fragment to be boldfaced, but not the first:
<pml-planet>
Venus</pml-planet>
<pml-planet
moons=
"1"
>
Earth</pml-planet>
<pml-planet
moons=
"2"
>
Mars</pml-planet>
In HTML documents, you can use this feature in a number of creative ways. For example, you could style all images that have an alt
attribute, thus highlighting those images that are correctly formed:
img
[
alt
]
{
border
:
3px
solid
red
;}
(This particular example is generally useful more for diagnostic purposes—that is, determining whether images are indeed correctly marked up—than for design purposes.)
If you wanted to boldface any element that includes title
information, which most browsers display as a “tool tip” when a cursor hovers over the element, you could write:
*[
title
]
{
font-weight
:
bold
;}
Similarly, you could style only those anchors (a
elements) that have an href
attribute, thus applying the styles to any hyperlink but not to any placeholder anchors.
It is also possible to select based on the presence of more than one attribute. You do this by chaining the attribute selectors together. For example, to boldface the text of any HTML hyperlink that has both an href
and a title
attribute, you would write:
a
[
href
][
title
]
{
font-weight
:
bold
;}
This would boldface the first link in the following markup, but not the second or third:
<a
href=
"http://www.w3.org/"
title=
"W3C Home"
>
W3C</a><br
/>
<a
href=
"http://www.webstandards.org"
>
Standards Info</a><br
/>
<a
title=
"Not a link"
>
dead.letter</a>
You can further narrow the selection process to encompass only those elements whose attributes are a certain value. For example, let’s say you want to boldface any hyperlink that points to a certain document on the web server. This would look something like:
a
[
href
=
"http://www.css-discuss.org/about.html"
]
{
font-weight
:
bold
;}
This will boldface the text of any a
element that has an href
attribute with exactly the value http://www.css-discuss.org/about.html. Any change at all, even dropping the www.
part or changing to a secure protocol with https
, will prevent a match.
Any attribute and value combination can be specified for any element. However, if that exact combination does not appear in the document, then the selector won’t match anything. Again, XML languages can benefit from this approach to styling. Let’s return to our PlanetML example. Suppose you want to select only those planet
elements that have a value of 1
for the attribute moons
:
planet
[
moons
=
"1"
]
{
font-weight
:
bold
;}
This would boldface the text of the second element in the following markup fragment, but not the first or third:
<planet>
Venus</planet>
<planet
moons=
"1"
>
Earth</planet>
<planet
moons=
"2"
>
Mars</planet>
As with attribute selection, you can chain together multiple attribute-value selectors to select a single document. For example, to double the size of the text of any HTML hyperlink that has both an href
with a value of http://www.w3.org/ and a title
attribute with a value of W3C Home
, you would write:
a
[
href
=
"http://www.w3.org/"
][
title
=
"W3C Home"
]
{
font-size
:
200%
;}
This would double the text size of the first link in the following markup, but not the second or third:
<a
href=
"http://www.w3.org/"
title=
"W3C Home"
>
W3C</a><br
/>
<a
href=
"http://www.webstandards.org"
title=
"Web Standards Organization"
>
Standards Info</a><br
/>
<a
href=
"http://www.example.org/"
title=
"W3C Home"
>
dead.link</a>
The results are shown in Figure 2-10.
Again, this format requires an exact match for the attribute’s value. Matching becomes an issue when the selector form encounters values that can in turn contain a space-separated list of values (e.g., the HTML attribute class
). For example, consider the following markup fragment:
<planet
type=
"barren rocky"
>
Mercury</planet>
The only way to match this element based on its exact attribute value is to write:
planet
[
type
=
"barren rocky"
]
{
font-weight
:
bold
;}
If you were to write planet[type="barren"]
, the rule would not match the example markup and thus would fail. This is true even for the class
attribute in HTML. Consider the following:
<p
class=
"urgent warning"
>
When handling plutonium, care must be taken to avoid the formation of a critical mass.</p>
To select this element based on its exact attribute value, you would have to write:
p
[
class
=
"urgent warning"
]
{
font-weight
:
bold
;}
This is not equivalent to the dot-class notation covered earlier, as we will see in the next section. Instead, it selects any p
element whose class
attribute has exactly the value "urgent warning"
, with the words in that order and a single space between them. It’s effectively an exact string match.
Also, be aware that ID selectors and attribute selectors that target the id
attribute are not precisely the same. In other words, there is a subtle but crucial difference between h1#page-title
and h1[id="page-title"]
. This difference is explained in “Specificity”.
Odds are that you’ll want to select elements based on portions of their attribute values, rather than the full value. For such situations, CSS actually offers a variety of options for matching substrings in an attribute’s value. These are summarized in Table 2-1.
Type | Description |
---|---|
|
Selects any element with an attribute |
|
Selects any element with an attribute |
|
Selects any element with an attribute |
|
Selects any element with an attribute |
|
Selects any element with an attribute |
The last of these attribute selectors that match on a partial subset of an element’s attribute value is actually easier to show than it is to describe. Consider the following rule:
*[
lang
|=
"en"
]
{
color
:
white
;}
This rule will select any element whose lang
attribute is equal to en
or begins with en-
. Therefore, the first three elements in the following example markup would be selected, but the last two would not:
<h1
lang=
"en"
>
Hello!</h1>
<p
lang=
"en-us"
>
Greetings!</p>
<div
lang=
"en-au"
>
G'day!</div>
<p
lang=
"fr"
>
Bonjour!</p>
<h4
lang=
"cy-en"
>
Jrooana!</h4>
In general, the form [att|="val"]
can be used for any attribute and its values. Let’s say you have a series of figures in an HTML document, each of which has a filename like figure-1.gif and figure-3.jpg. You can match all of these images using the following selector:
img
[
src
|=
"figure"
]
{
border
:
1px
solid
gray
;}
Or, if you’re creating a CSS framework or pattern library, instead of creating redundant classes like "btn btn-small btn-arrow btn-active"
, you can declare "btn-small-arrow-active"
, and target the class of elements with:
*[
class
|=
"btn"
]
{
border-radius
:
5px
;}
<
button
class
=
"btn-small-arrow-active"
>
Click
Me
</
button
>
The most common use for this type of attribute selector is to match language values, as demonstrated in an upcoming section, “The :lang Pseudo-Class”.
For any attribute that accepts a space-separated list of words, it is possible to select elements based on the presence of any one of those words. The classic example in HTML is the class
attribute, which can accept one or more words as its value. Consider our usual example text:
<p
class=
"urgent warning"
>
When handling plutonium, care must be taken to avoid the formation of a critical mass.</p>
Let’s say you want to select elements whose class
attribute contains the word warning
. You can do this with an attribute selector:
p
[
class
~=
"warning"
]
{
font-weight
:
bold
;}
Note the presence of the tilde (~
) in the selector. It is the key to selection based on the presence of a space-separated word within the attribute’s value. If you omit the tilde, you would have an exact value-matching attribute selector, as discussed in the previous section.
This selector construct is equivalent to the dot-class notation discussed in “Deciding Between Class and ID”. Thus, p.warning
and p[class~="warning"]
are equivalent when applied to HTML documents. Here’s an example that is an HTML version of the “PlanetML” markup seen earlier:
<span
class=
"barren rocky"
>
Mercury</span>
<span
class=
"cloudy barren"
>
Venus</span>
<span
class=
"life-bearing cloudy"
>
Earth</span>
To italicize all elements with the word barren
in their class
attribute, you write:
span
[
class
~=
"barren"
]
{
font-style
:
italic
;}
This rule’s selector will match the first two elements in the example markup and thus italicize their text, as shown in Figure 2-11. This is the same result we would expect from writing span.barren {font-style: italic;}
.
So why bother with the tilde-equals attribute selector in HTML? Because it can be used for any attribute, not just class
. For example, you might have a document that contains a number of images, only some of which are figures. You can use a partial-match value attribute selector aimed at the title
text to select only those figures:
img
[
title
~=
"Figure"
]
{
border
:
1px
solid
gray
;}
This rule selects any image whose title
text contains the word Figure
. Therefore, as long as all your figures have title
text that looks something like “Figure 4. A bald-headed elder statesman,” this rule will match those images. For that matter, the selector img[title~="Figure"]
will also match a title attribute with the value “How to Figure Out Who’s in Charge.” Any image that does not have a title
attribute, or whose title
value doesn’t contain the word “Figure,” won’t be matched.
Sometimes you want to select elements based on a portion of their attribute values, but the values in question aren’t space-separated lists of words. In these cases, you can use the form [att*="val"]
to match substrings that appear anywhere inside the attribute values. For example, the following CSS matches any span
element whose class
attribute contains the substring cloud
, so both “cloudy” planets are matched, as shown in Figure 2-12:
span
[
class
*=
"cloud"
]
{
font-style
:
italic
;}
<span
class=
"barren rocky"
>
Mercury</span>
<span
class=
"cloudy barren"
>
Venus</span>
<span
class=
"life-bearing cloudy"
>
Earth</span>
As you can imagine, there are many useful applications for this particular capability. For example, suppose you wanted to specially style any links to the O’Reilly website. Instead of classing them all and writing styles based on that class, you could instead write the following rule:
a
[
href
*=
"oreilly.com"
]
{
font-weight
:
bold
;}
You aren’t confined to the class
and href
attributes. Any attribute is up for grabs here: title
, alt
, src
, id
…if the attribute has a value, you can style based on a substring within that value. The following rule draws attention to any image with the string “space”
in its source URL:
img
[
src
*=
"space"
]
{
border
:
5px
solid
red
;}
Similarly, the following rule draws attention to input elements that have a title tells the user what to, and any other input whose title contains the substring “format” in its title:
input
[
title
*=
"format"
]
{
background-color
:
#dedede
;}
<input
type=
"tel"
title=
"Telephone number should be formatted as XXX-XXX-XXXX"
pattern=
"d{3}-d{3}-d{4}"
>
A common use for the general substring attribute selector is to match a section of a class in pattern library class names. Elaborating on the last example, we can target any class name that starts with "btn"
followed by a dash, and that contains the substring “arrow”
preceded by a dash:
*[
class
|=
"btn"
][
class
*=
"-arrow"
]
:after
{
content
:
"▼"
;}
<button
class=
"btn-small-arrow-active"
>
Click Me</button>
The matches are exact: if you include whitespace in your selector, then whitespace must also be present in an attribute’s value. The attribute names and values must be case-sensitive only if the underlying document language requires case sensitivity. Class names, titles, URLs, and ID values are all case-sensitive, but HTML attribute keyterm values, such as input types, are not:
input
[
type
=
"CHeckBoX"
]
{
margin-right
:
10px
;}
<input
type=
"checkbox"
name=
"rightmargin"
value=
"10px"
>
In cases where you want to select elements based on a substring at the beginning of an attribute value, then the attribute selector pattern [att^="val"]
is what you’re seeking. This can be particularly useful in a situation where you want to style types of links differently, as illustrated in Figure 2-13.
a
[
href
^=
"https:"
]
{
font-weight
:
bold
;}
a
[
href
^=
"mailto:"
]
{
font-style
:
italic
;}
Another use case is when you want to style all images in an article that are also figures, as in the figures you see throughout this text. Assuming that the alt text of each figure begins with text in the pattern “Figure 5”—which is an entirely reasonable assumption in this case—then you can select only those images as follows:
img
[
alt
^=
"Figure"
]
{
border
:
2px
solid
gray
;
display
:
block
;
margin
:
2em
auto
;}
The potential drawback here is that any img
element whose alt
starts with “Figure” will be selected, whether or not it’s meant to be an illustrative figure. The likeliness of that occurring depends on the document in question.
Another use case is selecting all of the calendar events that occur on Mondays. In this case, let’s assume all of the events have a title
attribute containing a date in the format “Monday, March 5th, 2012.” Selecting them all is a simple matter of [title^="Monday"]
.
The mirror image of beginning-substring matching is ending-substring matching, which is accomplished using the [att$="val"]
pattern. A very common use for this capability is to style links based on the kind of resource they target, such as separate styles for PDF documents, as illustrated in Figure 2-14.
a
[
href
$
=
".pdf"
]
{
font-weight
:
bold
;}
Similarly, you could (for whatever reason) select images based on their image format:
img
[
src
$
=
".gif"
]
{
...
}
img
[
src
$
=
".jpg"
]
{
...
}
img
[
src
$
=
".png"
]
{
...
}
To continue the calendar example from the previous section, it would be possible to select all of the events occurring within a given year using a selector like [title$="2015"]
.
You may have noticed that I’ve quoted all the attribute values in the attribute selectors. Quoting is required if the value includes any special characters, begins with a dash or digit, or is otherwise invalid as an identifier and needs to be quoted as a string. To be safe, I recommend always quoting attribute values in attribute selectors, even though it is only required to makes strings out of invalid identifiers.
CSS Selectors level 4 introduces a case-insensitivity option to attribute selectors. Including an i
before the closing bracket will allow the selector to match attribute values case-insensitively, regardless of document language rules.
For example, suppose you want to select all links to PDF documents, but you don’t know if they’ll end in .pdf, .PDF, or even .Pdf. Here’s how:
a
[
href
$
=
'.PDF'
i
]
Adding that humble little i
means the selector will match any a
element whose href
attribute’s value ends in .pdf
, regardless of the capitalization of the letters P, D, and F.
This case-insensitivity option is available for all attribute selectors we’ve covered. Note, however, that this only applies to the values in the attribute selectors. It does not enforce case insensitivity on the attribute names themselves. Thus, in a case-sensitive language, planet[type*="rock" i]
will match all of the following:
<planet
type=
"barren rocky"
>
Mercury</planet>
<planet
type=
"cloudy ROCKY"
>
Venus</planet>
<planet
type=
"life-bearing Rock"
>
Earth</planet>
It will not match the following element, because the attribute TYPE
isn’t matched by type
:
<planet
TYPE=
"dusty rock"
>
Mars</planet>
Again, that’s in languages that enforce case sensitivity in the element and attribute syntax. XHTML was one such. In languages that are case-insensitive, like HTML5, this isn’t an issue.
As of late 2017, Opera Mini, the Android browser, and Edge did not support this capability.
CSS is powerful because it uses the structure of documents to determine appropriate styles and how to apply them. Yet structure plays a much larger role in the way styles are applied to a document. Let’s take a moment to discuss structure before moving on to more powerful forms of selection.
To understand the relationship between selectors and documents, we need to once again examine how documents are structured. Consider this very simple HTML document:
<html>
<head>
<base
href=
"http://www.meerkat.web/"
>
<title>
Meerkat Central</title>
</head>
<body>
<h1>
Meerkat<em>
Central</em></h1>
<p>
Welcome to Meerkat<em>
Central</em>
, the<strong>
best meerkat web site on<a
href=
"inet.html"
>
the<em>
entire</em>
Internet</a></strong>
!</p>
<ul>
<li>
We offer:<ul>
<li><strong>
Detailed information</strong>
on how to adopt a meerkat</li>
<li>
Tips for living with a meerkat</li>
<li><em>
Fun</em>
things to do with a meerkat, including:<ol>
<li>
Playing fetch</li>
<li>
Digging for food</li>
<li>
Hide and seek</li>
</ol>
</li>
</ul>
</li>
<li>
...and so much more!</li>
</ul>
<p>
Questions?<a
href=
"mailto:[email protected]"
>
Contact us!</a>
</p>
</body>
</html>
Much of the power of CSS is based on the parent-child relationship of elements. HTML documents (actually, most structured documents of any kind) are based on a hierarchy of elements, which is visible in the “tree” view of the document (see Figure 2-15). In this hierarchy, each element fits somewhere into the overall structure of the document. Every element in the document is either the parent or the child of another element, and it’s often both.
An element is said to be the parent of another element if it appears directly above that element in the document hierarchy. For example, in Figure 2-15, the first p
element is parent to the em
and strong
elements, while strong
is parent to an anchor (a
) element, which is itself parent to another em
element. Conversely, an element is the child of another element if it is directly beneath the other element. Thus, the anchor element in Figure 2-15 is a child of the strong
element, which is in turn child to the p
element, which is itself child to the body
, and so on.
The terms “parent” and “child” are specific applications of the terms ancestor and descendant. There is a difference between them: in the tree view, if an element is exactly one level above or below another, then they have a parent-child relationship. If the path from one element to another is traced through two or more levels, the elements have an ancestor-descendant relationship, but not a parent-child relationship. (A child is also a descendant, and a parent is also an ancestor.) In Figure 2-15, the first ul
element is parent to two li
elements, but the first ul
is also the ancestor of every element descended from its li
element, all the way down to the most deeply nested li
elements.
Also, in Figure 2-15, there is an anchor that is a child of strong
, but also a descendant of p
, body
, and html
elements. The body
element is an ancestor of everything that the browser will display by default, and the html
element is ancestor to the entire document. For this reason, in an HTML or XHTML document, the html
element is also called the root element.
The first benefit of understanding this model is the ability to define descendant selectors (also known as contextual selectors). Defining descendant selectors is the act of creating rules that operate in certain structural circumstances but not others. As an example, let’s say you want to style only those em
elements that are descended from h1
elements. You could put a class
attribute on every em
element found within an h1
, but that’s almost as time-consuming as using the font
tag. It’s far more efficient to declare rules that match only em
elements that are found inside h1
elements.
To do so, write the following:
h1
em
{
color
:
gray
;}
This rule will make gray any text in an em
element that is the descendant of an h1
element. Other em
text, such as that found in a paragraph or a block quote, will not be selected by this rule. Figure 2-16 makes this clear.
In a descendant selector, the selector side of a rule is composed of two or more space-separated selectors. The space between the selectors is an example of a combinator. Each space combinator can be translated as “found within,” “which is part of,” or “that is a descendant of,” but only if you read the selector right to left. Thus, h1 em
can be translated as, “Any em
element that is a descendant of an h1
element.” (To read the selector left to right, you might phrase it something like, “Any h1
that contains an em
will have the following styles applied to the em
.”)
You aren’t limited to two selectors. For example:
ul
ol
ul
em
{
color
:
gray
;}
In this case, as Figure 2-17 shows, any emphasized text that is part of an unordered list that is part of an ordered list that is itself part of an unordered list (yes, this is correct) will be gray. This is obviously a very specific selection criterion.
Descendant selectors can be extremely powerful. They make possible what could never be done in HTML—at least not without oodles of font
tags. Let’s consider a common example. Assume you have a document with a sidebar and a main area. The sidebar has a blue background, the main area has a white background, and both areas include lists of links. You can’t set all links to be blue because they’d be impossible to read in the sidebar.
The solution: descendant selectors. In this case, you give the element that contains your sidebar a class of sidebar
and enclose the main area in a main
element. Then, you write styles like this:
.sidebar
{
background
:
blue
;}
main
{
background
:
white
;}
.sidebar
a
:link
{
color
:
white
;}
main
a
:link
{
color
:
blue
;}
Figure 2-18 shows the result.
:link
refers to links to resources that haven’t been visited. We’ll talk about it in detail in “Hyperlink pseudo-classes”.
Here’s another example: let’s say that you want gray to be the text color of any b
(boldface) element that is part of a blockquote
and for any bold text that is found in a normal paragraph:
blockquote b, p b {color: gray;}
The result is that the text within b
elements that are descended from paragraphs or block quotes will be gray.
One overlooked aspect of descendant selectors is that the degree of separation between two elements can be practically infinite. For example, if you write ul em
, that syntax will select any em
element descended from a ul
element, no matter how deeply nested the em
may be. Thus, ul em
would select the em
element in the following markup:
<ul>
<li>
List item 1<ol>
<li>
List item 1-1</li>
<li>
List item 1-2</li>
<li>
List item 1-3<ol>
<li>
List item 1-3-1</li>
<li>
List item<em>
1-3-2</em></li>
<li>
List item 1-3-3</li>
</ol>
</li>
<li>
List item 1-4</li>
</ol>
</li>
</ul>
A more subtle aspect of descendant selectors is that they have no notion of element proximity. In other words, the closeness of two elements within the document tree has no bearing on whether a rule applies or not. This is important when it comes to specificity (which we’ll cover later on) and when considering rules that might appear to cancel each other out.
For example, consider the following (which contains a selector type we’ll discuss in the upcoming section, “The Negation Pseudo-Class”):
div
:not
(
.help
)
span
{
color
:
gray
;}
div
.help
span
{
color
:
red
;}
<div
class=
"help"
>
<div
class=
"aside"
>
This text contains<span>
a span element</span>
within.</div>
</div>
What the CSS says, in effect, is “any span
inside a div
that doesn’t have a class
containing the word help
should be gray” in the first rule, and “any span
inside a div
whose class
contains the word help
” in the second rule. In the given markup fragment, both rules apply to the span
shown.
Because the two rules have equal weight and the “red” rule is written last, it wins out and the span
is red. The fact that the div class="aside"
is “closer to” the span
than the div class="help"
is irrelevant. Again: descendant selectors have no notion of element proximity. Both rules match, only one color can be applied, and due to the way CSS works, red is the winner here. (We’ll discuss why in the next chapter.)
In some cases, you don’t want to select an arbitrarily descended element. Rather, you want to narrow your range to select an element that is a child of another element. You might, for example, want to select a strong
element only if it is a child (as opposed to any level of descendant) of an h1
element. To do this, you use the child combinator, which is the greater-than symbol (>
):
h1
>
strong
{
color
:
red
;}
This rule will make red the strong
element shown in the first h1
, but not the second:
<h1>
This is<strong>
very</strong>
important.</h1>
<h1>
This is<em>
really<strong>
very</strong></em>
important.</h1>
Read right to left, the selector h1 > strong
translates as, “Selects any strong
element that is a direct child of an h1
element.” The child combinator can be optionally surrounded by whitespace. Thus, h1 > strong
, h1> strong
, and h1>strong
are all equivalent. You can use or omit whitespace as you wish.
When viewing the document as a tree structure, it’s easy to see that a child selector restricts its matches to elements that are directly connected in the tree. Figure 2-19 shows part of a document tree.
In this tree fragment, you can pick out parent-child relationships. For example, the a
element is parent to the strong
, but it is child to the p
element. You could match elements in this fragment with the selectors p > a
and a > strong
, but not p > strong
, since the strong
is a descendant of the p
but not its child.
You can also combine descendant and child combinations in the same selector. Thus, table.summary td > p
will select any p
element that is a child of a td
element that is itself descended from a table
element that has a class
attribute containing the word summary
.
Let’s say you want to style the paragraph immediately after a heading, or give a special margin to a list that immediately follows a paragraph. To select an element that immediately follows another element with the same parent, you use the adjacent-sibling combinator, represented as a plus symbol (+
). As with the child combinator, the symbol can be surrounded by whitespace, or not, at the author’s discretion.
To remove the top margin from a paragraph immediately following an h1
element, write:
h1
+
p
{
margin-top
:
0
;}
The selector is read as, “Selects any p
element that immediately follows an h1
element that shares a parent with the p
element.”
To visualize how this selector works, it is easiest to once again consider a fragment of a document tree, shown in Figure 2-20.
In this fragment, a pair of lists descends from a div
element, one ordered and the other not, each containing three list items. Each list is an adjacent sibling, and the list items themselves are also adjacent siblings. However, the list items from the first list are not siblings of the second, since the two sets of list items do not share the same parent element. (At best, they’re cousins, and CSS has no cousin selector.)
Remember that you can select the second of two adjacent siblings only with a single combinator. Thus, if you write li + li {font-weight
: bold;}
, only the second and third items in each list will be boldfaced. The first list items will be unaffected, as illustrated in Figure 2-21.
To work properly, CSS requires that the two elements appear in “source order.” In our example, an ol
element is followed by a ul
element. This allows us to select the second element with ol + ul
, but we cannot select the first using the same syntax. For ul + ol
to match, an ordered list must immediately follow an unordered list.
Keep in mind that text content between two elements does not prevent the adjacent-sibling combinator from working. Consider this markup fragment, whose tree view would be the same as that shown in Figure 2-19:
<div>
<ol>
<li>
List item 1</li>
<li>
List item 1</li>
<li>
List item 1</li>
</ol>
This is some text that is part of the 'div'.<ul>
<li>
A list item</li>
<li>
Another list item</li>
<li>
Yet another list item</li>
</ul>
</div>
Even though there is text between the two lists, we can still match the second list with the selector ol + ul
. That’s because the intervening text is not contained with a sibling element, but is instead part of the parent div
. If we wrapped that text in a paragraph element, it would then prevent ol + ul
from matching the second list. Instead, we might have to write something like ol + p + ul
.
As the following example illustrates, the adjacent-sibling combinator can be used in conjunction with other combinators:
html
>
body
table
+
ul
{
margin-top
:
1.5em
;}
The selector translates as, “Selects any ul
element that immediately follows a sibling table
element that is descended from a body
element that is itself a child of an html
element.”
As with all combinators, you can place the adjacent-sibling combinator in a more complex setting, such as div#content h1 + div ol
. That selector is read as, “Selects any ol
element that is descended from a div
when the div
is the adjacent sibling of an h1
which is itself descended from a div
whose id
attribute has a value of content
.”
Selectors Level 3 introduced a new sibling combinator called the general sibling combinator. This lets you select any element that follows another element when both elements share the same parent, represented using the tilde (~
) combinator.
As an example, to italicize any ol
that follows an h2
and also shares a parent with the h2
, you’d write h2 ~ol {font-style: italic;}
. The two elements do not have to be adjacent siblings, although they can be adjacent and still match this rule. The result of applying this rule to the following markup is shown in Figure 2-22:
<div>
<h2>
Subheadings</h2>
<p>
It is the case that not every heading can be a main heading. Some headings must be subheadings. Examples include:</p>
<ol>
<li>
Headings that are less important</li>
<li>
Headings that are subsidiary to more important headlines</li>
<li>
Headings that like to be dominated</li>
</ol>
<p>
Let's restate that for the record:</p>
<ol>
<li>
Headings that are less important</li>
<li>
Headings that are subsidiary to more important headlines</li>
<li>
Headings that like to be dominated</li>
</ol>
</div>
As you can see, both ordered lists are italicized. That’s because both of them are ol
elements that follow an h2
with which they share a parent (the div
).
Things get really interesting with pseudo-class selectors. These selectors let you assign styles to what are, in effect, phantom classes that are inferred by the state of certain elements, or markup patterns within the document, or even by the state of the document itself.
The phrase “phantom classes” might seem a little odd, but it really is the best way to think of how pseudo-classes work. For example, suppose you wanted to highlight every other row of a data table. You could do that by marking up every other row something like class="even"
and then writing CSS to highlight rows with that class—or (as we’ll soon see) you could use a pseudo-class selector to achieve the same effect, and through very similar means.
Before we start, a word about chaining. CSS makes it possible to combine (“chain”) pseudo-classes together. For example, you can make unvisited links red when they’re hovered and visited links maroon when they’re hovered:
a
:link:hover
{
color
:
red
;}
a
:visited:hover
{
color
:
maroon
;}
The order you specify doesn’t actually matter; you could also write a:hover:link
to the same effect as a:link:hover
. It’s also possible to assign separate hover styles to unvisited and visited links that are in another language—for example, German:
a
:link:hover:lang
(
de
)
{
color
:
gray
;}
a
:visited:hover:lang
(
de
)
{
color
:
silver
;}
Be careful not to combine mutually exclusive pseudo-classes. For example, a link cannot be both visited and unvisited, so a:link:visited
doesn’t make any sense and will never match anything.
The majority of pseudo-classes are structural in nature; that is, they refer to the markup structure of the document. Most of them depend on patterns within the markup, such as choosing every third paragraph, but others allow you to address specific types of elements. All pseudo-classes, without exception, are a word preceded by a single colon (:
), and they can appear anywhere in a selector.
Before we get started, there’s an aspect of pseudo-classes that needs to be made explicit here: pseudo-classes always refer to the element to which they’re attached, and no other. Seems like a weirdly obvious thing to say, right? The reason to make it explicit is that for a few of the structural pseudo-classes, it’s a common error to think they are descriptors that refer to descendant elements.
To illustrate this, I’d like to share a personal anecdote. When my first child was born in 2003, I announced it online (like you do). A number of people responded with congratulations and CSS jokes, chief among them the selector #ericmeyer:first-child
. The problem there is that selector would select me, not my daughter, and only if I were the first child of my parents (which, as it happens, I am). To properly select my first child, that selector would need to be #ericmeyer > :first-child
.
The confusion is understandable, which is why I’m addressing it here. Reminders will be found throughout the following sections. Just always keep in mind that the effect of pseudo-classes is to apply a sort of a “phantom class” to the element to which they’re attached, and you should be OK.
This is the quintessence of structural simplicity: the pseudo-class :root
selects the root element of the document. In HTML, this is always the html
element. The real benefit of this selector is found when writing stylesheets for XML languages, where the root element may be different in every language—for example, in RSS 2.0 it’s the rss
element—or even when you have more than one possible root element within a single language (though not a single document!).
Here’s an example of styling the root element in HTML, as illustrated in Figure 2-23:
:root
{
border
:
10px
dotted
gray
;}
body
{
border
:
10px
solid
black
;}
In HTML documents, you can always select the html
element directly, without having to use the :root
pseudo-class. There is a difference between the two selectors in terms of specificity, which we’ll cover in Chapter 3.
With the pseudo-class :empty
, you can select any element that has no children of any kind, including text nodes, which covers both text and whitespace. This can be useful in suppressing elements that a CMS has generated without filling in any actual content. Thus, p:empty {display: none;}
would prevent the display of any empty paragraphs.
Note that in order to be matched, an element must be, from a parsing perspective, truly empty—no whitespace, visible content, or descendant elements. Of the following elements, only the first and last would be matched by p:empty
:
<p></p>
<p>
</p>
<p>
</p>
<p>
<!—-a comment-->
</p>
The second and third paragraphs are not matched by :empty
because they are not empty: they contain, respectively, a single space and a single newline character. Both are considered text nodes, and thus prevent a state of emptiness. The last paragraph matches because comments are not considered content, not even whitespace. But put even one space or newline to either side of that comment, and p:empty
would fail to match.
You might be tempted to just style all empty elements with something like *:empty {display: none;}
, but there’s a hidden catch: :empty
matches HTML’s empty elements, like img
and input
. It could even match textarea
, unless you insert some default text into the textarea
element. Thus, in terms of matching elements, img
and img:empty
are effectively the same. (They are different in terms of specificity, which we’ll cover in the next chapter.)
<img
src=
"salmon.png"
alt=
"North Pacific Salmon"
>
<br>
<input
type=
"number"
min=
"-1"
max=
"1"
step=
".01"
/>
<textarea></textarea>
If you’ve ever wanted to select all the images that are wrapped by a hyperlink element, the :only-child
pseudo-class is for you. It selects elements when they are the only child element of another element. So let’s say you want to add a border to any image that’s the only child of another element. You’d write:
img
:only-child
{
border
:
1px
solid
black
;}
This would match any image that meets those criteria. Therefore, if you had a paragraph which contained an image and no other child elements, the image would be selected regardless of all the text surrounding it. If what you’re really after is images that are sole children and found inside hyperlinks, then you just modify the selector like so (which is illustrated in Figure 2-24):
a
[
href
]
img
:only-child
{
border
:
2px
solid
black
;}
<a
href=
"http://w3.org/"
><img
src=
"w3.png"
alt=
"W3C"
></a>
<a
href=
"http://w3.org/"
><img
src=
"w3.png"
alt=
""
>
The W3C</a>
<a
href=
"http://w3.org/"
><img
src=
"w3.png"
alt=
""
>
<em>
The W3C</em></a>
There are two things to remember about :only-child
. The first is that you always apply it to the element you want to be an only child, not to the parent element, as explained earlier. And that brings up the second thing to remember, which is that when you use :only-child
in a descendant selector, you aren’t restricting the elements listed to a parent-child relationship.
To go back to the hyperlinked-image example, a[href] img:only-child
matches any image that is an only child and is descended from an a
element, not is a child of an a
element. To match, the element image must be the only child of its direct parent, and a descendant of a link, but that parent can itself be a descendant of that link. Therefore, all three of the images here would be matched, as shown in Figure 2-25:
a
[
href
]
img
:only-child
{
border
:
5px
solid
black
;}
<a
href=
"http://w3.org/"
><img
src=
"w3.png"
alt=
"W3C"
></a>
<a
href=
"http://w3.org/"
><span><img
src=
"w3.png"
alt=
"W3C"
></span></a>
<a
href=
"http://w3.org/"
>
A link to<span>
the<img
src=
"w3.png"
alt=
""
>
web</span>
site</a>
In each case, the image is the only child element of its parent, and it is also descended from an a
element. Thus, all three images are matched by the rule shown. If you wanted to restrict the rule so that it matched images that were the only children of a
elements, then you’d just add the child combinator to yield a[href] > img:only-child
. With that change, only the first of the three images shown in Figure 2-25 would be matched.
That’s all great, but what if you want to match images that are the only images inside hyperlinks, but there are other elements in there with them? Consider the following:
<a
href=
"http://w3.org/"
><b>
•</b><img
src=
"w3.png"
alt=
"W3C"
></a>
In this case, we have an a
element that has two children: b
and img
. That image, no longer being the only child of its parent (the hyperlink), can never be matched using :only-child
. However, it can be matched using :only-of-type
. This is illustrated in Figure 2-26:
a
[
href
]
img
:only-of-type
{
border
:
5px
solid
black
;}
<a
href=
"http://w3.org/"
><b>
•</b><img
src=
"w3.png"
alt=
"W3C"
></a>
<a
href=
"http://w3.org/"
><span><b>
•</b><img
src=
"w3.png"
alt=
"W3C"
></span></a>
The difference is that :only-of-type
will match any element that is the only of its type among all its siblings, whereas :only-child
will only match if an element has no siblings at all.
This can be very useful in cases such as selecting images within paragraphs without having to worry about the presence of hyperlinks or other inline elements:
p
>
img
:only-of-type
{
float
:
right
;
margin
:
20px
;}
As long as there aren’t multiple images that are children of the same paragraph, then the image will be floated. You could also use this pseudo-class to apply extra styles to an h2
when it’s the only one in a section of a document, like this:
section
>
h2
{
margin
:
1em
0
0.33em
;
font-size
:
1.8rem
;
border-bottom
:
1px
solid
gray
;}
section
>
h2
:only-of-type
{
font-size
:
2.4rem
;}
Given those rules, any section
that has only one child h2
will have it appear larger than usual. If there are two or more h2
children to a section
, neither of them will be larger than the other. The presence of other children—whether they are other heading levels, paragraphs, tables, paragraphs, lists, and so on—will not interfere with matching.
There’s one more thing to make clear, which is that :only-of-type
refers to elements and nothing else. Consider the following:
p
.unique
:only-of-type
{
color
:
red
;}
<div>
<p
class=
"unique"
>
This paragraph has a 'unique' class.</p>
<p>
This paragraph doesn't have a class at all.</p>
</div>
In this case, neither of the paragraphs will be selected. Why not? Because there are two paragraphs that are descendants of the div
, so neither of them can be the only one of their type.
The class name is irrelevant here. We’re fooled into thinking that “type” is a generic description, because of how we parse language. Type, in the way :only-of-type
means it, refers only to the element type. Thus, p.unique:only-of-type
means “select any p
element whose class
attribute contains the word unique
when the p
element is the only p
element among its siblings.” It does not mean “select any p
element whose class
attribute contains the word unique
when it’s the only sibling paragraph to meet that criterion.”
It’s pretty common to want to apply special styling to the first or last child of an element. A common example is styling a bunch of navigation links in a tab bar, and wanting to put some special visual touches on the first or last tab (or both). In the past, this was done by applying special classes to those elements. Now we have pseudo-classes to carry the load for us.
The pseudo-class :first-child
is used to select elements that are the first children of other elements. Consider the following markup:
<div>
<p>
These are the necessary steps:</p>
<ul>
<li>
Insert key</li>
<li>
Turn key<strong>
clockwise</strong></li>
<li>
Push accelerator</li>
</ul>
<p>
Do<em>
not</em>
push the brake at the same time as the accelerator.</p>
</div>
In this example, the elements that are first children are the first p
, the first li
, and the strong
and em
elements, which are all the first children of their respective parents. Given the following two rules:
p
:first-child
{
font-weight
:
bold
;}
li
:first-child
{
text-transform
:
uppercase
;}
we get the result shown in Figure 2-27.
The first rule boldfaces any p
element that is the first child of another element. The second rule uppercases any li
element that is the first child of another element (which, in HTML, must be either an ol
or ul
element).
As has been mentioned, the most common error is assuming that a selector like p:first-child
will select the first child of a p
element. Remember the nature of pseudo-classes, which is to attach a sort of phantom class to the element associated with the pseudo-class. If you were to add actual classes to the markup, it would look like this:
<
div
>
<
p
class
=
"first-child"
>
These
are
the
necessary
steps
:</
p
>
<
ul
>
<
li
class
=
"first-child"
>
Insert
key
</
li
>
<
li
>
Turn
key
<
strong
class
=
"first-child"
>
clockwise
</
strong
></
li
>
<
li
>
Push
accelerator
</
li
>
</
ul
>
<
p
>
Do
<
em
class
=
"first-child"
>
not
</
em
>
push
the
brake
at
the
same
time
as
the
accelerator
.
</
p
>
</
div
>
Therefore, if you want to select those em
elements that are the first child of another element, you write em:first-child
.
The mirror image of :first-child
is :last-child
. If we take the previous example and just change the pseudo-classes, we get the result shown in Figure 2-28.
p
:last-child
{
font-weight
:
bold
;}
li
:last-child
{
text-transform
:
uppercase
;}
<div>
<p>
These are the necessary steps:</p>
<ul>
<li>
Insert key</li>
<li>
Turn key<strong>
clockwise</strong></li>
<li>
Push accelerator</li>
</ul>
<p>
Do<em>
not</em>
push the brake at the same time as the accelerator.</p>
</div>
The first rule boldfaces any p
element that is the last child of another element. The second rule uppercases any li
element that is the last child of another element. If you wanted to select the em
element inside that last paragraph, you could use the selector p:last-child em
, which selects any em
element that descends from a p
element that is itself the last child of another element.
Interestingly, you can combine these two pseudo-classes to create a version of :only-child
. The following two rules will select the same elements:
p
:only-child
{
color
:
red
;}
p
:first-child:last-child
{
background-color
:
red
;}
Either way, we get paragraphs with red foreground and background colors (not a good idea, clearly).
In a manner similar to selecting the first and last children of an element, you can select the first or last of a type of element within another element. This permits things like selecting the first table
inside a given element, regardless of whatever elements come before it.
table
:first-of-type
{
border-top
:
2px
solid
gray
;}
Note that this does not apply to the entire document; that is, the rule shown will not select the first table in the document and skip all the others. It will instead select the first table
element within each element that contains one, and skip any sibling table
elements that come after the first. Thus, given the document structure shown in Figure 2-29, the circled nodes are the ones that are selected.
Within the context of tables, a useful way to select the first data cell within a row regardless of whether a header cell comes before it in the row is as follows:
td
:first-of-type
{
border-left
:
1px
solid
red
;}
That would select the first data cell in each of the following table rows:
<tr>
<th
scope=
"row"
>
Count</th><td>
7</td><td>
6</td><td>
11</td>
</tr>
<tr>
<td>
Q</td><td>
X</td><td>
-</td>
</tr>
Compare that to the effects of td:first-child
, which would select the first td
element in the second row, but not in the first row.
The flip side is :last-of-type
, which selects the last instance of a given type from amongst its sibling elements. In a way, it’s just like :first-of-type
except you start with the last element in a group of siblings and walk backward toward the first element until you reach an instance of the type. Given the document structure shown in Figure 2-30, the circled nodes are the ones selected by table:last-of-type
.
As was noted with :only-of-type
, remember that you are selecting elements of a type from among their sibling elements; thus, every set of siblings is considered separately. In other words, you are not selecting the first (or last) of all the elements of a type within the entire document as a single group. Each set of elements that share a parent is its own group, and you can select the first (or last) of a type within each group.
Similar to what was noted in the previous section, you can combine these two pseudo-classes to create a version of :only-of-type
. The following two rules will select the same elements:
table
:only-of-type
{
color
:
red
;}
table
:first-of-type:last-of-type
{
background
:
red
;}
If you can select elements that are the first, last, or only children of other elements, how about every third child? All even children? Only the ninth child? Rather than define a literally infinite number of named pseudo-classes, CSS has the :nth-child()
pseudo-class. By filling integers or even simple algebraic expressions into the parentheses, you can select any arbitrarily numbered child element you like.
Let’s start with the :nth-child()
equivalent of :first-child
, which is :nth-child(1)
. In the following example, the selected elements will be the first paragraph and the first list item.
p
:nth-child
(
1
)
{
font-weight
:
bold
;}
li
:nth-child
(
1
)
{
text-transform
:
uppercase
;}
<div>
<p>
These are the necessary steps:</p>
<ul>
<li>
Insert key</li>
<li>
Turn key<strong>
clockwise</strong></li>
<li>
Push accelerator</li>
</ul>
<p>
Do<em>
not</em>
push the brake at the same time as the accelerator.</p>
</div>
If we change the numbers from 1
to 2
, however, then no paragraphs will be selected, and the middle (or second) list item will be selected, as illustrated in Figure 2-31:
p
:nth-child
(
2
)
{
font-weight
:
bold
;}
li
:nth-child
(
2
)
{
text-transform
:
uppercase
;}
You can insert any integer you choose; if you have a use case for selecting any ordered list that is the 93rd child element of its parent, then ol:nth-child(93)
is ready to serve. This will match the 93rd child of any parent as long as that child is an ordered list. (This does not mean the 93rd ordered list among its siblings; see the next section for that.)
More powerfully, you can use simple algebraic expressions in the form a n
+ b or a n
− b to define recurring instances, where a and b are integers and n
is present as itself. Furthermore, the +
b or −
b part is optional and thus can be dropped if it isn’t needed.
Let’s suppose we want to select every third list item in an unordered list, starting with the first. The following makes that possible, selecting the first and fourth items, as shown in Figure 2-32.
ul
>
li
:nth-child
(
3n
+
1
)
{
text-transform
:
uppercase
;}
The way this works is that n
represents the series 0, 1, 2, 3, 4, and on into infinity. The browser then solves for 3 n + 1, yielding 1, 4, 7, 10, 13, and so on. Were we to drop the +1
, thus leaving us with simply 3n
, the results would be 0, 3, 6, 9, 12, and so on. Since there is no zeroth list item—all element counting starts with one, to the likely chagrin of array-slingers everywhere—the first list item selected by this expression would be the third list item in the list.
Given that element counting starts with one, it’s a minor trick to deduce that :nth-child(2n)
will select even-numbered children, and either :nth-child(2n+1)
or :nth-child(2n-1)
will select odd-numbered children. You can commit that to memory, or you can use the two special keywords that :nth-child()
accepts: even
and odd
. Want to highlight every other row of a table, starting with the first? Here’s how you do it, with the results shown in Figure 2-33:
tr
:nth-child
(
odd
)
{
background
:
silver
;}
Anything more complex than every-other-element requires an an + b
expression.
Note that when you want to use a negative number for b
, you have to remove the +
sign or else the selector will fail entirely. Of the following two rules, only the first will do anything. The second will be dropped by the parser and ignored:
tr
:nth-child
(
4n
-
2
)
{
background
:
silver
;}
tr
:nth-child
(
3n
+
−
2
)
{
background
:
red
;}
If you want to select every row starting with the ninth, you can use either of the following. They are similar in that they will select all rows starting with the ninth, but the latter one has greater specificity, which we discuss in Chapter 3:
tr
:nth-child
(
n
+
9
)
{
background
:
silver
;}
tr
:nth-child
(
8
)
~
tr
{
background
:
silver
;}
As you might expect, there is a corresponding pseudo-class in :nth-last-child()
. This lets you do the same thing as :nth-child()
, except with :nth-last-child()
you start from the last element in a list of siblings and count backward toward the beginning. If you’re intent on highlighting every other table row and making sure the very last row is one of the rows in the highlighting pattern, either one of these will work for you:
tr
:nth-last-child
(
odd
)
{
background
:
silver
;}
tr
:nth-last-child
(
2n
+
1
)
{
background
:
silver
;}
/* equivalent */
If the DOM is updated to add or remove table rows, there is no need to add or remove classes. By using structural selectors, these selectors will always match the odd rows of the updated DOM.
Any element can be matched using both :nth-child()
and :nth-last-child()
if it fits the criteria. Consider these rules, the results of which are shown in Figure 2-34:
li
:nth-child
(
3n
+
3
)
{
border-left
:
5px
solid
black
;}
li
:nth-last-child
(
4n
-
1
)
{
border-right
:
5px
solid
black
;
background
:
silver
;}
It’s also the case that you can string these two pseudo-classes together as :nth-child(1):nth-last-child(1)
, thus creating a more verbose restatement of :only-child
. There’s no real reason to do so other than to create a selector with a higher specificity, but the option is there.
You can use CSS to determine how many list items are in a list, and style them accordingly:
li
:only-child
{
width
:
100%
;}
li
:nth-child
(
1
)
:nth-last-child
(
2
),
li
:nth-child
(
2
)
:nth-last-child
(
1
)
{
width
:
50%
;}
li
:nth-child
(
1
)
:nth-last-child
(
3
),
li
:nth-child
(
1
)
:nth-last-child
(
3
)
~
li
{
width
:
33.33%
;}
li
:nth-child
(
1
)
:nth-last-child
(
4
),
li
:nth-child
(
1
)
:nth-last-child
(
4
)
~
li
{
width
:
25%
;}
In these examples, if a list item is the only list item, then the width is 100%. If a list item is the first item and also the second-from-the-last item, that means there are two items, and the width is 50%. If an item is the first item and also the third from the last item, then we make it, and the two sibling list items following it, 33% wide. Similarly, if a list item is the first item and also the fourth from the last item, it means that there are exactly four items, so we make it, and its three siblings, 25% of the width.
In what’s probably become a familiar pattern, the :nth-child()
and :nth-last-child()
pseudo-classes have analogues in :nth-of-type()
and :nth-last-of-type()
. You can, for example, select every other hyperlink that’s a child of any given paragraph, starting with the second, using p > a:nth-of-type(even)
. This will ignore all other elements (span
s, strong
s, etc.) and consider only the links, as demonstrated in Figure 2-35:
p
>
a
:nth-of-type
(
even
)
{
background
:
blue
;
color
:
white
;}
If you want to work from the last hyperlink backward, then you’d use p >
a:nth-last-of-type(even)
.
As before, these select elements of a type from among their sibling elements, not from among all the elements of a type within the entire document as a single group. Each element has its own list of siblings, and selections happen within each group.
As you might expect, you can string these two together as :nth-of-type(1):nth-last-of-type(1)
to restate :only-of-type
, only with higher specificity. (We will explain specificity in Chapter 3, I promise.)
Beyond the structural pseudo-classes, there are a set of pseudo-classes that relate to structure but can change based on changes made to the page after it’s been rendered. In other words, the styles are applied to pieces of a document based on something in addition to the structure of the document, and in a way that cannot be precisely deduced simply by studying the document’s markup.
It may sound like we’re applying styles at random, but not so. Instead, we’re applying styles based on somewhat ephemeral conditions that can’t be predicted in advance. Nevertheless, the circumstances under which the styles will appear are, in fact, well-defined. Think of it this way: during a sporting event, whenever the home team scores, the crowd will cheer. You don’t know exactly when during a game the team will score, but when it does, the crowd will cheer, just as predicted. The fact that you can’t predict the exact moment of the cheer doesn’t make it any less expected.
Consider the anchor element (a
), which (in HTML and related languages) establishes a link from one document to another. Anchors are always anchors, but some anchors refer to pages that have already been visited, while others refer to pages that have yet to be visited. You can’t tell the difference by simply looking at the HTML markup, because in the markup, all anchors look the same. The only way to tell which links have been visited is by comparing the links in a document to the user’s browser history. So there are actually two basic types of links: visited and unvisited.
CSS2.1 defines two pseudo-classes that apply only to hyperlinks. In HTML, these are any a
elements with an href
attribute; in XML languages, they’re any elements that act as links to another resource. Table 2-2 describes the pseudo-classes you can apply to them.
Name | Description |
---|---|
|
Refers to any anchor that is a hyperlink (i.e., has an |
|
Refers to any anchor that is a hyperlink to an already visited address. For security reasons, the styles that can be applied to visited links are severely limited; see sidebar “Visited Links and Privacy” for details. |
The first of the pseudo-classes in Table 2-2 may seem a bit redundant. After all, if an anchor hasn’t been visited, then it must be unvisited, right? If that’s the case, all we should need is the following:
a
{
color
:
blue
;}
a
:visited
{
color
:
red
;}
Although this format seems reasonable, it’s actually not quite enough. The first of the rules shown here applies not only to unvisited links, but also to placeholder links such as this one:
<a>
4. The Lives of Meerkats</a>
The resulting text would be blue because the a
element will match the rule a {color
: blue;}
. Therefore, to avoid applying your link styles to placeholders, use the :link
and :visited
pseudo-classes:
a
:link
{
color
:
blue
;}
/* unvisited links are blue */
a
:visited
{
color
:
red
;}
/* visited links are red */
This is a good place to revisit attribute and class selectors and show how they can be combined with pseudo-classes. For example, let’s say you want to change the color of links that point outside your own site. In most circumstances we can use the starts-with attribute selector. However, some CMS’s set all links to be absolute URLs, in which case you could assign a class to each of these anchors. It’s easy:
<a
href=
"/about.html"
>
My About page</a>
<a
href=
"https://www.site.net/"
class=
"external"
>
An external site</a>
To apply different styles to the external link, all you need is a rule like this:
a
.external
:link
,
a
[
href
^=
"http"
]
:link
{
color
:
slateblue
;}
a
.external
:visited
,
a
[
href
^=
"http"
]
:visited
{
color
:
maroon
;}
This rule will make the second anchor in the preceding markup slateblue by default, and maroon once visited, while the first anchor will remain the default color for hyperlinks (usually blue when not visited and purple once visited). For improved usability and accessibility, visited links should be easily differentiable from non-visited links.
Styled visited links enable visitors to know where they have been and what they have yet to visit. This is especially important on large websites where it may be difficult to remember, especially for those with cognitive disabilities, which pages have been visited. Not only is highlighting visited links one of the W3C Web Content Accessibility Guidelines, but it makes searching for content faster, more efficient, and less stressful for everyone.
The same general syntax is used for ID selectors as well:
a
#footer-copyright
:link
{
background
:
yellow
;}
a
#footer-copyright
:visited
{
background
:
gray
;}
You can chain the two link-state pseudo-classes together, but there’s no reason why you ever would: a link cannot be both visited and unvisited at the same time!
CSS defines a few pseudo-classes that can change a document’s appearance based on actions taken by the user. These dynamic pseudo-classes have traditionally been used to style hyperlinks, but the possibilities are much wider. Table 2-3 describes these pseudo-classes.
Name | Description |
---|---|
|
Refers to any element that currently has the input focus—i.e., can accept keyboard input or be activated in some way. |
|
Refers to any element over which the mouse pointer is placed—e.g., a hyperlink over which the mouse pointer is hovering. |
|
Refers to any element that has been activated by user input—e.g., a hyperlink on which a user clicks during the time the mouse button is held down. |
Elements that can become :active
include links, buttons, menu items, and any element with a tabindex value. These elements and all other interactive elements, including form controls and elements that are content-editable, can also receive focus.
As with :link
and :visited
, these pseudo-classes are most familiar in the context of hyperlinks. Many web pages have styles that look like this:
a
:link
{
color
:
navy
;}
a
:visited
{
color
:
gray
;}
a
:focus
{
color
:
orange
;}
a
:hover
{
color
:
red
;}
a
:active
{
color
:
yellow
;}
The order of the pseudo-classes is more important than it might seem at first. The usual recommendation is “link-visited-hover-active,” although this has been modified to “link-visited-focus-hover-active.” The next chapter explains why this particular ordering is important and discusses several reasons you might choose to change or even ignore the recommended ordering.
Notice that the dynamic pseudo-classes can be applied to any element, which is good since it’s often useful to apply dynamic styles to elements that aren’t links. For example, using this markup:
input
:focus
{
background
:
silver
;
font-weight
:
bold
;}
you could highlight a form element that is ready to accept keyboard input, as shown in Figure 2-36.
You can also perform some rather odd feats by applying dynamic pseudo-classes to arbitrary elements. You might decide to give users a “highlight” effect by way of the following:
body
*
:hover
{
background
:
yellow
;}
This rule will cause any element that’s descended from the body
element to display a yellow background when it’s in a hover state. Headings, paragraphs, lists, tables, images, and anything else found inside the body
will be changed to have a yellow background. You could also change the font, put a border around the element being hovered, or alter anything else the browser will allow.
Dynamic pseudo-classes present some interesting issues and peculiarities. For example, it’s possible to set visited and unvisited links to one font size and make hovered links a larger size, as shown in Figure 2-37:
a
:link
,
a
:visited
{
font-size
:
13px
;}
a
:hover
,
a
:active
{
font-size
:
20px
;}
As you can see, the user agent increases the size of the anchor while the mouse pointer hovers over it; or, thanks to the :active
setting, when a user touches it on a touch screen. A user agent that supports this behavior must redraw the document while an anchor is in hover state, which could force a reflow of all the content that follows the link.
Closely related to the dynamic pseudo-classes are the user-interface (UI) state pseudo-classes, which are summarized in Table 2-4. These pseudo-classes allow for styling based on the current state of user-interface elements like checkboxes.
Name | Description |
---|---|
|
Refers to user-interface elements (such as form elements) that are enabled; that is, available for input. |
|
Refers to user-interface elements (such as form elements) that are disabled; that is, not available for input. |
|
Refers to radio buttons or checkboxes that have been selected, either by the user or by defaults within the document itself. |
|
Refers to radio buttons or checkboxes that are neither checked nor unchecked; this state can only be set via DOM scripting, and not due to user input. |
|
Refers to the radio button, checkbox, or option that was selected by default. |
|
Refers to a user input that meets all of its data validity semantics |
|
Refers to a user input that does not meet all of its data validity semantics |
|
Refers to a user input whose value is between the minimum and maximum values |
|
Refers to a user input whose value is below the minimum or above the maximum values allowed by the control |
|
Refers to a user input that must have a value set |
|
Refers to a user input that does not need to have a value set |
|
Refers to a user input that is editable by the user |
|
Refers to a user input that is not editable by the user |
Although the state of a UI element can certainly be changed by user action—for example, a user checking or unchecking a checkbox—UI-state pseudo-classes are not classified as purely dynamic because they can also be affected by the document structure or DOM scripting.
You might think that :focus
belongs in this section, not the previous section. However, the Selectors Level 3 specification groups :focus
in with :hover
and :active
. This is most likely because they were grouped together in CSS2, which had no UI-state pseudo-classes. More importantly, though, focus can be given to non-UI elements, such as headings or paragraphs—one example is when they are read by a speaking browser. That alone keeps it from being considered a UI-state pseudo-class.
Thanks to both DOM scripting and HTML5, it is possible to mark a user-interface element (or group of user interface elements) as being disabled. A disabled element is displayed, but cannot be selected, activated, or otherwise interacted with by the user. Authors can set an element to be disabled either through DOM scripting, or (in HTML5) by adding a disabled
attribute to the element’s markup.
Any element that hasn’t been disabled is by definition enabled. You can style these two states using the :enabled
and :disabled
pseudo-classes. It’s much more common to style disabled elements and leave enabled elements alone, but both have their uses, as illustrated in Figure 2-38:
:enabled
{
font-weight
:
bold
;}
:disabled
{
opacity
:
0
.
5
;}
In addition to being enabled or disabled, certain UI elements can be checked or unchecked—in HTML, the input types “checkbox” and “radio” fit this definition. Selectors level 3 offers a :checked
pseudo-class to handle elements in that state, though curiously it omits an :unchecked
. There is also the :indeterminate
pseudo-class, which matches any checkable UI element that is neither checked nor unchecked. These states are illustrated in Figure 2-39:
:checked
{
background
:
silver
;}
:indeterminate
{
border
:
red
;}
In addition, you can use the negation pseudo-class, which is covered later, to select checkboxes which are not checked with input[type="checkbox"]:not(:checked)
. Only radio buttons and checkboxes can be checked. All other elements, and these two when not checked, are :not(:checked)
.
Although checkable elements are unchecked by default, it’s possible for a HTML author to toggle them on by adding the checked
attribute to an element’s markup. An author can also use DOM scripting to flip an element’s checked state to checked or unchecked, whichever they prefer.
There is a third state, “indeterminate.” As of late 2017, this state can only be set through DOM scripting or by the user agent itself; there is no markup-level method to set elements to an indeterminate state. The purpose of allowing an indeterminate state is to visually indicate that the element needs to be checked (or unchecked) by the user. However, note that this is purely a visual effect: it does not affect the underlying state of the UI element, which is either checked or unchecked, depending on document markup and the effects of any DOM scripting.
Although the previous examples show styled radio buttons, remember that direct styling of radio buttons and checkboxes with CSS is actually very limited. However, that shouldn’t limit your use of the selected-option pseudo-classes. As an example, you can style the labels associated with your checkboxes and radio buttons using a combination of :checked
and the adjacent sibling combinator:
input
[
type
=
"checkbox"
]
:checked
+
label
{
color
:
red
;
font-style
:
italic
;
}
<input
id=
"chbx"
type=
"checkbox"
>
<label
for=
"chbx"
>
I am a label</label>
The :default
pseudo-class matches the UI elements that are the default among a set of similar elements. This typically applies to context menu items, buttons, and select lists/menus. If there are several same-named radio buttons, the one that was originally checked matches :default
, even if the UI has been updated by the user so that it no longer matches :checked
. If a checkbox was checked on page load, :default
matches it. Any initially-selected option
(s) in a select
element will match. The :default
pseudo-class can also match buttons and menu items:
[
type
=
"checkbox"
]
:default
+
label
{
font-style
:
italic
;
}
<input
type=
"checkbox"
id=
"chbx"
checked
name=
"foo"
value=
"bar"
>
<label
for=
"chbx"
>
This was checked on page load</label>
The pseudo-class :required
matches any form control that is required, as denoted by the presence of the required
attribute (in HTML5). The :optional
pseudo-class matches form controls that do not have the required
attribute, or whose required
attribute has a value of false
.
A form element is :required
or :optional
if a value for it is, respectively, required or optional before the form to which it belongs can be validly submitted. For example:
input
:required
{
border
:
1px
solid
#f00
;}
input
:optional
{
border
:
1px
solid
#ccc
;}
<input
type=
"email"
placeholder=
"enter an email address"
required
>
<input
type=
"email"
placeholder=
"optional email address"
>
<input
type=
"email"
placeholder=
"optional email address"
required=
"false"
>
The first email input will match the :required
pseudo-class because of the presence of the required
attribute. The second input is optional, and therefore will match the :optional
pseudo-class. The same is true for the third input, which has a required
attribute, but the value is false
.
We could also use attribute selectors instead. The following selectors are equivalent to the preceding ones:
input
[
required
]
{
border
:
1px
solid
#f00
;}
input
:not
([
required
])
{
border
:
1px
solid
#ccc
;}
Elements that are not form-input elements can be neither required nor optional.
The :valid
pseudo-class refers to a user input that meets all of its data validity requirements. The :invalid
pseudo-class, on the other hand, refers to a user input that does not meet all of its data validity requirements.
The validity pseudo-classes :valid
and :invalid
only apply to elements having the capacity for data validity requirements: a div
will never match either selector, but an input
could match either, depending on the current state of the interface.
Here’s an example where an image is dropped into the background of any email input which has focus, with one image being used when the input is invalid and another used when the input is valid, as illustrated in Figure 2-40:
input
[
type
=
"email"
]
:focus
{
background-position
:
100%
50%
;
background-repeat
:
no-repeat
;
}
input
[
type
=
"email"
]
:focus:invalid
{
background-image
:
url(warning.jpg)
;
}
input
[
type
=
"email"
]
:focus:valid
{
background-image
:
url(checkmark.jpg)
;
}
<input
type=
"email"
>
These pseudo-class states are dependent on what the user agent reports to its own style system, and so may not act as you might expect. For example, in late 2017, an empty email input matched :valid
in multiple user agents, despite the fact a null input is not a valid email address. Until these validation routines improve, it is best to treat the validity pseudo-classes with caution.
The range pseudo-classes include :in-range
, which refers to a user input whose value is between the minimum and maximum values set by HTML5’s min
and max
attributes, and :out-of-range
, which refers to a user input whose value is below the minimum or above the maximum values allowed by the control.
For example, consider a number input that accepts numbers in the range 0 to 1,000:
input
[
type
=
"number"
]
:focus
{
background-position
:
100%
50%
;
background-repeat
:
no-repeat
;
}
input
[
type
=
"number"
]
:focus:out-of-range
{
background-image
:
url(warning.jpg)
;
}
input
[
type
=
"number"
]
:focus:in-range
{
background-image
:
url(checkmark.jpg)
;
}
<input
id=
"nickels"
type=
"number"
min=
"0"
max=
"1000"
/>
The :in-range
and :out-of-range
pseudo-classes apply only to elements with range limitations. Elements that don’t have range limitations, like links for inputs of type tel
, will not be matched by either pseudo-class.
There is also a step
attribute in HTML5. If a value is invalid because it does not match the step value, but is still between or equal to the min
and max
values, it will match :invalid
while also still matching :in-range
. That is to say, a value can be in-range while also being invalid.
Thus, in the following scenario, the input’s value will be both red and boldfaced, because 23
is in range but is not evenly divisible by 10:
input
[
type
=
"number"
]
:invalid
{
color
:
red
;}
input
[
type
=
"number"
]
:in-range
{
font-weight
:
bold
;}
<input
id=
"by-tens"
type=
"number"
min=
"0"
max=
"1000"
step=
"10"
value=
"23"
/>
The mutability pseudo-classes include :read-write
, which refers to a user input that is editable by the user; and :read-only
, which matches user inputs that are not editable. Only elements that have the capacity to be altered by user input can match :read-write
.
For example, in HTML, a non-disabled, non-read-only input
element is :read-write
, as is any element with the contenteditable
attribute. Everything else matches :read-only
:
By default, neither of the following rules would ever match: textarea
elements are read-write, and pre
elements are read-only.
textarea
:read-only
{
opacity
:
0
.
75
;}
pre
:read-write:hover
{
border
:
1px
dashed
green
;}
However, each can be made to match as follows:
<textarea
disabled
></textarea>
<pre
contenteditable
>
Type your own code!</pre>
Because the textarea
is given a disabled
attribute, it becomes read-only, and so will have the first rule apply. Similarly, the pre
here has been given the attribute contenteditable
, so now it is a read-write element. This will be matched by the second rule.
When a URL includes a fragment identifier, the piece of the document at which it points is called (in CSS) the target. Thus, you can uniquely style any element that is the target of a URL fragment identifier with the :target
pseudo-class.
Even if you’re unfamiliar with the term “fragment identifier,” you’ve probably seen them in action. Consider this URL:
http://www.w3.org/TR/css3-selectors/#target-pseudo
The target-pseudo
portion of the URL is the fragment identifier, which is marked by the #
symbol. If the referenced page (http://www.w3.org/TR/css3-selectors/) has an element with an ID of target-pseudo
, then that element becomes the target of the fragment identifier.
Thanks to :target
, you can highlight any targeted element within a document, or you can devise different styles for various types of elements that might be targeted—say, one style for targeted headings, another for targeted tables, and so on. Figure 2-41 shows an example of :target
in action:
*
:target
{
border-left
:
5px
solid
gray
;
background
:
yellow
url(target.png)
top
right
no-repeat
;}
:target
styles will not be applied in two circumstances:
If the page is accessed via a URL that does not have a fragment identifier
If the page is accessed via a URL that has a fragment identifier, but the identifier does not match any elements within the document
More interestingly, though, what happens if multiple elements within a document can be matched by the fragment identifier—for example, if the author erroneously included three separate instances of <div
id="target-pseudo">
in the same document?
The short answer is that CSS doesn’t have or need rules to cover this case, because all CSS is concerned with is styling targets. Whether the browser picks just one of the three elements to be the target or designates all three as co-equal targets, :target
styles should be applied to anything that is a valid target.
For situations where you want to select an element based on its language, you can use the :lang()
pseudo-class. In terms of its matching patterns, the :lang()
pseudo-class is similar to the |=
attribute selector. For example, to italicize elements whose content is written in French, you could write either of the following:
*
:lang
(
fr
)
{
font-style
:
italic
;}
*[
lang
|=
"fr"
]
{
font-style
:
italic
;}
The primary difference between the pseudo-class selector and the attribute selector is that language information can be derived from a number of sources, some of which are outside the element itself. For the attribute selector, the element must have the attribute present to match. The :lang
pseudo-class, on the other hand, matches descendants of an element with the language declaration. As Selectors Level 3 states:
In HTML, the language is determined by a combination of the
lang
attribute, and possibly information from themeta
elements and the protocol (such as HTTP headers). XML uses an attribute calledxml:lang
, and there may be other document language-specific methods for determining the language.
The pseudo-class will operate on all of that information, whereas the attribute selector can only work if there is a lang
attribute present in the element’s markup. Therefore, the pseudo-class is more robust than the attribute selector and is probably a better choice in most cases where language-specific styling is needed.
Every selector we’ve covered thus far has had one thing in common: they’re all positive selectors. In other words, they are used to identify the things that should be selected, thus excluding by implication all the things that don’t match and are thus not selected.
For those times when you want to invert this formulation and select elements based on what they are not, Selectors Level 3 introduced the negation pseudo-class, :not()
. It’s not quite like any other selector, fittingly enough, and it does have some restrictions on its use, but let’s start with an example.
Let’s suppose you want to apply a style to every list item that doesn’t have a class
of moreinfo
, as illustrated in Figure 2-42. That used to be very difficult, and in certain cases impossible, to make happen. If we wanted all the list items to be italic except those with the class .moreinfo
, we used to declare all the links as italic, generally having to target the ul
with a class, then normalize back based on the class, making sure the override came last in the source order, and had equal or higher specificity. Now we can declare:
li
:not
(
.moreinfo
)
{
font-style
:
italic
;}
The way :not()
works is that you attach it to an element, and then in the parentheses you fill in a simple selector. A simple selector, according to the W3C, is:
either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.
Basically, a simple selector is a selector with no ancestral-descendant relationship.
Note the “either” there: you can only use one of those inside :not()
. You can’t group them and you can’t combine them using combinators, which means you can’t use a descendant selector, because the space separating elements in a descendant selector is a combinator. Those restrictions may (indeed most likely will) be lifted in the future, but we can still do quite a lot even within the given constraints.
For example, let’s flip around the previous example and select all elements with a class
of moreinfo
that are not list items. This is illustrated in Figure 2-43:
.moreinfo
:not
(
li
)
{
font-style
:
italic
;}
Translated into English, the selector would say, “Select all elements with a class
whose value contains the word moreinfo
as long as they are not li
elements.” Similarly, the translation of li:not(.moreinfo)
would be “Select all li
elements as long as they do not have a class
whose value contains the word moreinfo
.”
Technically, you can put a universal selector into the parentheses, but there’s very little point. After all, p:not(*)
would mean “Select any p
element as long as it isn’t any element,” and there’s no such thing as an element that is not an element. Very similar to that would be p:not(p)
, which would also select nothing. It’s also possible to write things like p:not(div)
, which will select any p
element that is not a div
element—in other words, all of them. Again, there is very little reason to do so.
You can also use the negation pseudo-class at any point in a more complex selector. Thus, to select all tables that are not children of a section
element, you would write *:not(section) > table
. Similarly, to select table header cells that are not part of the table header, you’d write something like table *:not(thead)
> tr > th
, with a result like that shown in Figure 2-44.
What you cannot do is nest negation pseudo-classes; thus, p:not(:not(p))
is invalid and will be ignored. It’s also, logically, the equivalent of just writing p
, so there’s no point anyway. Furthermore, you cannot reference pseudo-elements (which we’ll cover shortly) inside the parentheses, since they are not simple selectors.
On the other hand, it’s possible to chain negations together to create a sort of “and also not this” effect. For example, you might want to select all elements with a class
of link
that are neither list items nor paragraphs:
*
.link
:not
(
li
)
:not
(
p
)
{
font-style
:
italic
;}
That translates to “Select all elements with a class
whose value contains the word link
as long as they are neither li
nor p
elements.”
One thing to watch out for is that you can have situations where rules combine in unexpected ways, mostly because we’re not used to thinking of selection in the negative. Consider this test case:
div
:not
(
.one
)
p
{
font-weight
:
normal
;}
div
.one
p
{
font-weight
:
bold
;}
<div
class=
"one"
>
<div
class=
"two"
>
<p>
I'm a paragraph!</p>
</div>
</div>
The paragraph will be boldfaced, not normal-weight. This is because both rules match: the p
element is descended from a div
whose class
does not contain the word one
(<div class="two">
), but it is also descended from a div
whose class
contains the word one
. Both rules match, and so both apply. Since there is a conflict, the cascade is used to resolve the conflict, and the second rule wins. The structural arrangement of the markup, with the div.two
being “closer” to the paragraph than div.one
, is irrelevant.
Much as pseudo-classes assign phantom classes to anchors, pseudo-elements insert fictional elements into a document in order to achieve certain effects. Four basic pseudo-elements were defined in CSS 2, and they let you style the first letter of an element, style the first line of an element, and both create and style “before” and “after” content. There are other pseudo-classes that have been defined since CSS 2 (e.g., ::marker
), and we’ll explore those in the chapters of the book for which they’re relevant. The four from CSS2 will be covered here because they’re old-school, and because they make a convenient way to talk about pseudo-element behavior.
Unlike the single colon of pseudo-classes, pseudo-elements employ a double-colon syntax, like ::first-line
. This is meant to distinguish pseudo-elements from pseudo-classes. This was not always the case—in CSS2, both selector types used a single colon—so for backward compatibility, browsers will accept single-colon pseudo-element selectors. Don’t take this as an excuse to be sloppy, though! Use the proper number of colons at all times in order to future-proof your CSS; after all, there is no way to predict when browsers will stop accepting single-colon pseudo-element selectors.
Note that all pseudo-elements must be placed at the very end of the selector in which they appear. It would not be legal to write p::first-line em
since the pseudo-element comes before the subject of the selector (the subject is the last element listed). This also means that only one pseudo-element is permitted in a given selector, though that restriction may be eased in future versions of CSS.
The ::first-letter
pseudo-element styles the first letter, or a leading punctuation character and the first letter (if the text starts with punctuation), of any non-inline element. This rule causes the first letter of every paragraph to be colored red:
p
::first-letter
{
color
:
red
;}
The ::first-letter
pseudo-element is most commonly used to create an “initial cap” or “drop cap” typographic effect. You could make the first letter of each p
twice as big as the rest of the heading, though you may want to only apply this styling to the first letter of the first paragraph:
p
:first-of-type::first-letter
{
font-size
:
200%
;}
The result of this rule is illustrated in Figure 2-45.
This rule effectively causes the user agent to style a fictional, or “faux” element, that encloses the first letter of each p
. It would look something like this:
<p><p-first-letter>
T</p-first-letter>
his is a p element, with a styled first letter</h2>
The ::first-letter
styles are applied only to the contents of the fictional element shown in the example. This <p-first-letter>
element does not appear in the document source, nor even in the DOM tree. Instead, its existence is constructed on the fly by the user agent and is used to apply the ::first-letter
style(s) to the appropriate bit of text. In other words, <p-first-letter>
is a pseudo-element. Remember, you don’t have to add any new tags. The user agent styles the first letter for you as if you had encased it in a styled element.
The first letter is defined as the first typographic letter unit of the originating element, if it is not preceded by other content, like an image. The specifications use “letter unit” because some languages have letters made up of more than character, like “oe” in Norse. Punctuation that precedes or follows the first letter unit, even if there are several such symbols, are included in the ::first-letter
pseudo-element.
Similarly, ::first-line
can be used to affect the first line of text in an element. For example, you could make the first line of each paragraph in a document large and purple:
p
::first-line
{
font-size
:
150%
;
color
:
purple
;
}
In Figure 2-46, the style is applied to the first displayed line of text in each paragraph. This is true no matter how wide or narrow the display region is. If the first line contains only the first five words of the paragraph, then only those five words will be big and purple. If the first line contains the first 30 words of the element, then all 30 will be big and purple.
Because the text from “This” to “only” should be big and purple, the user agent employs a fictional markup that looks something like this:
<p>
<p-first-line>
This is a paragraph of text that has only</p-first-line>
one stylesheet applied to it. That style causes the first line to be big and purple. No other line will have those styles applied.</p>
If the first line of text were edited to include only the first seven words of the paragraph, then the fictional </p-first-line>
would move back and occur just after the word “that.” If the user were to increase or decrease the font-size rendering, or expand or contract the browser window causing the width of the text to change, thereby causing the number of words on the first line to increase or decrease, the browser automatically sets only the words in the currently displayed first line to be both big and purple.
The length of the first line depends on a number of factors, including the font-size, letter spacing, width of the parent container, etc. Depending on the markup, and the length of that first line, it is possible that the end of the first line comes in the middle of a nested element. If the ::first-line
breaks up a nested element, such as an em
or a hyperlink, the properties attached to the ::first-line
will only apply to the portion of that nested element that is displayed on the first line.
The ::first-letter
and ::first-line
pseudo-elements currently can be applied only to block-display elements such as headings or paragraphs, and not to inline-display elements such as hyperlinks. There are also limits on the CSS properties that may be applied to ::first-line
and ::first-letter
. Table 2-5 gives an idea of these limitations.
::first-letter | ::first-line |
---|---|
|
|
Let’s say you want to preface every h2
element with a pair of silver square brackets as a typographical effect:
h2
::before
{
content
:
"]]"
;
color
:
silver
;}
CSS lets you insert generated content, and then style it directly using the pseudo-elements ::before
and ::after
. Figure 2-47 illustrates an example.
The pseudo-element is used to insert the generated content and to style it. To place content after an element, use the pseudo-element ::after
. You could end your documents with an appropriate finish:
body
::after
{
content
:
"The End."
;}
Generated content is a separate subject, and the entire topic (including more detail on ::before
and ::after
) is covered more thoroughly in Chapter 15.
By using selectors based on the document’s language, authors can create CSS rules that apply to a large number of similar elements just as easily as they can construct rules that apply in very narrow circumstances. The ability to group together both selectors and rules keeps stylesheets compact and flexible, which incidentally leads to smaller file sizes and faster download times.
Selectors are the one thing that user agents usually must get right because the inability to correctly interpret selectors pretty much prevents a user agent from using CSS at all. On the flip side, it’s crucial for authors to correctly write selectors because errors can prevent the user agent from applying the styles as intended. An integral part of correctly understanding selectors and how they can be combined is a strong grasp of how selectors relate to document structure and how mechanisms—such as inheritance and the cascade itself—come into play when determining how an element will be styled.