As explained earlier, the purpose of the selector is to select elements to be affected by various CSS rules. Selectors always appear before a {
in a CSS rule.
I'll use quite a few properties you haven't seen before, but their names are pretty much self-explanatory.
Three selectors have been around since the very beginning and are universal to all browsers that support CSS:
class
attribute.id
attribute.A type selector selects elements according to their type—that is, their element name. For example, the type of element selected could be a third-level header; therefore the type would be h3
. The desired effect: To display third-level headers by using a different font than what's used on the computer, centering the text and making it larger, and having a black solid line 1 pixel thick above and below the header. Here are the declarations:
font-family:"Copperplate Gothic Light", serif;
1text-align:center;
font-size:150%;
2border-style:solid;
border-color:black;
border-top-width:1px;
border-bottom-width:1px;
border-left:0;
3border-right:0;
3Notes:
Serifis simply a
Plan Bfor the browser in case the computer does not have
Copperplate Gothic Lightinstalled. You may have as long a list of fonts as you like in this context.)
150% the size of the text in the parent element.Be careful, or you may end up with some very large text indeed.
0in the context of borders, it means that you don't want a border to appear at all. Therefore, you don't need to specify
border-left-width
, -color
, or -style
(same goes for the border on the right). More on this when I talk about borders in Borders, Padding, And Margins: The CSS Box Model.This set of rules will therefore look like this:
It is common practice to put multiple declarations on separate lines for the sake of readabilty:
Now, to specify that you want this rule to apply to the h3
element, the selector should be h3
. Do not use the <
or >
symbols, just the element name.
h3
Element)And the results are:
Below is the code of the page in its entirety:
Now, wouldn't you agree that this is a lot better than
repeated every time you wanted a third-level header?h3
style="font-family:"Copperplate Gothic Light", serif; text-align:center; font-size:150%; border-style:solid; border-color:black; border-top-width:1px; border-bottom-width:1px; border-left:0; border-right:0;"
The class selector takes focus off the element name and concentrates on what group the element is a part of, which is defined by the class
attribute. The selector in this case consists of a period followed by the class name.
So say we have two classes that describe how loudly someone is speaking. The classes are:
The contents of an element with the "whisper"
class
is to be in small text, while the contents of an element with the "yell"
class
should be large. Therefore, we set up the classes like this:
In this case, I have the entire rule on one line since it saves space without sacrificing readability.
The code of the page looks like this:
Now, it would have been more semantic to use a q
element or at least a span
element, but I wanted to make a point about presentational markup. Look closely:
By giving the big
element the whisper
class and the small
element the yell
class, their effects are completely reversed—which nullifies any use they might have.
Another example would be found in the code I used to describe the div
element back in Block Elements. Here is the original code:
Here, I can put the foreign
class
to work by deciding that all elements with the foreign
class
are in italics, allowing me to remove the style
attribute (which cuts down on code).
I also want the paragraph that holds the Lorem Ipsum
text to be in italics for the same reason, so I add the foreign
class
to that paragraph as well. Note that I'm not adding this class to the paragraph containing the Lorem Ipsum
text because I want it in italics; I want the Lorem Ipsum
text in italics because the text is not in English, which gives the foreign
class semantic meaning to go with its effect.
And here is the result:
This is the most specific selector of all—it specifies one and only one element, using that element's identity. Just to remind you, in (X)HTML, an element's identity is specified in its id
attribute. This type of selector is usually used for layouts, selecting elements that are given highly specialized roles.
While class
-based selectors are preceded by a period, identity-based selectors are preceded by a hash mark (#
).
In this case, I'm going to use an example from Block Elements, in which I demonstrated div
elements.
Around the div
element with the identity Lorem_Ipsum_Example
, I want to put a 1-pixel solid black border. Therefore, I add the following rule:
I don't need to specify top
, bottom
, left
or right
since this border will go all the way around. The
property creates space between the border and the content.padding
For good measure, let's round off this demonstration of basic selectors by saying that the text of the h1
element should be underlined and that anything with the foreign
class be in italics.
h1
ElementThe final code for all of this is:
The type, class, and identity selectors will do a lot for you, but the last two require you to use those attributes and the first might be a bit broad. In CSS 2, 4 new types of selectors were added.
Some pseudo-classes and pseudo-elements were introduced in CSS 1, but they really didn't become popular until CSS 2
The universal selector selects everything, and its symbol is *
. It's not commonly used, but if you want every single element to have a black, solid border one pixel in width all the way around, this would be the selector to use.
Behold the result:
This has the bonus of being a very nice demonstration of nesting.
Type, class, and id selectors are far and away the most common selectors, and the universal selector gets quite a bit of use as well. You can create quite a good style sheet using just these. But the following selectors, although they are less common, may suit your purposes well. But be warned: they aren't supported by all browsers.
Other attributes can be specified in selectors but rarely are for one major reason: Internet Explorer has a long history of getting its knickers in a twist over a lot of things and this type of selector is one of them. To put it shortly, while Firefox, Opera, Safari, and other browsers have supported such methods for years, it wasn't until Internet Explorer 7 (released in 2006) that Internet Explorer supported this as well. Considering earlier versions of Internet Explorer are reasonably popular (nearly 20% of all people who use a browser use IE4 - 6), it is still likely that someone will be using one of those browsers, and therefore won't be able to properly view a page styled using these selectors.
The syntax for attribute selectors is a little more complex than what we've seen so far. To begin with, an attribute selector be contained within square brackets, like this:
This is important. If you, say, want to select all elements with a title
attribute, but forgot the brackets, the browser would instead select the title
element. There's not much you can do with a title element, but that's what the browser would select. On the other hand, if you intended to select an h3
element, but had h3
inside square brackets, it would look for elements with an h3
attribute—an attribute that does not exist in (X)HTML.
It is possible to select elements by the mere presence of a specific attribute.
In the following example, all quotes with a lang
attribute are in italics:
Thus, all elements with a lang
attribute will be in italics. It is total coincidence that in this case, both such elements are q
elements.
What if I don't want English phrases to be in italics, because English is not (to me) a foreign language? In other words, I want all elements with a lang
attribute to be in italics, except when that attribute specifies English as the language. I can, in this case, make an exception for all attributes with the exact value of en
, which is the code for English.
As before, the selector is contained within square brackets ([ ]
). And, as before, you use the attribute name (in this case, lang
). However, you would follow lang
with an equal sign and the value of the attribute in quotations. Below is the selector in its entirety (the part that specifies the value en
is highlighted):
Since this is intended to be an exception to the rule, it would follow the more general rule pertaining to all elements containing a lang
attribute.
This means that every element that has a lang
attribute with the exact value of en
will be displayed normally.
There are variations of this, all depending on what symbol accompanies the equal sign. The first three were introduced in CSS 2, the rest in CSS 3.
Example: [lang="en"]
The lang
attribute has a value of exactly en
.
Example: [lang|="en"]
The value en
begins a hyphen-separated list of values or is on its own. This allows for values of en-CA
, en-UK
, or en-US
(Canadian, British, or American English, respectively) as well as en
alone.
Example: [lang~="en"]
The value en
is one of a space-separated list of values (for example, lang="fr en de"
) or is on its own. This selector works a lot like the class selector (and indeed, class selectors could be written this way), but this is universal to all attributes. On the downside, this is not universal all browsers.
Example: [lang^="en"]
The lang
attribute begins with the text en
. This selector would match something like lang="english"
, but not lang="fr en de"
.
Example: [lang$="ca"]
The href
attribute ends with the text ca
. For example, it would match lang="en-ca"
but not lang="en-ca en-uk"
.
Example: [lang*="en-ca"]
The href
attribute has the text en-ca
somewhere in it. This would match lang="en=uk en-ca en-bb"
Pseudo-classes select elements according to characteristics that are not specified in their attributes, element name, or their ancestor elements (I'll get to that last bit later on in the chapter). The three exceptions are marked with asterisks. Pseudoclass names are preceded by a colon (:
). The pseudo-classes are:
CSS 3 was made a recommendation only in 2011, so not all browsers will support it.
There are two pseudo-classes that are exclusively for hyperlinks: :link
and :visited
. Along with active
are the oldest pseudo-classes, debuting in CSS 1. These two pseudo-classes allow you to control the appearance of hyperlinks, both unclicked (through :link
) and clicked (through :visited
).
I give these rather short shrift because, if you've been to any websites where links are different colours depending on whether or not you've been to the pages they point to, you know the effects already. I will, however, make a note on the order these pseudoclasses should be in for them to have the proper effect:
*I cover this in Dynamic Pseudo-Classes
below.
The dynamic pseudo-classes allow for some interaction with the webpages beyond simply clicking on links.
Again, I'm giving these short shrift because you already have an idea of how pseudo-classes work.
activebetween the time you press down the mouse button while the mouse cursor is over that element and the time you release the mouse button—in other words, when you are actually clicking on the element.
:focus
means is that the form element has been selected to accept input.a
element) and the colour or something like that changes? This is the pseudo-class that allows you to do that.The pseudo-classes introduced in CSS 3 are for the form interface elements: input
, button
, select
and textarea
. I describe these in greater detail in Forms
:enabled
) or not (:disabled
).These pseudoclasses select elements according to which child of the parent element they are. There are ten such selectors and two that fit the group in other ways. They are:
The :first-child
pseudoclass, the oldest (introduced in CSS 2) and thus most common child pseudoclass, applies to any element that is the first child element of its parent element. Used alone like this, it will first apply to the first child of the body
element, then the first child element of every element within the body, their first child elements, and so on. This will apply to neither the body
nor html
element. The body
element is not the first child of the html
element (that's head
, which does not appear on the webpage and thus gets no styling) and the html
element (the root element) is not a child element at all.
Below is the code of a page that puts a border around every element that is the first child of another element.
The result is:
The rest were introduced in CSS 3, and are not supported by a majority of browsers yet. Use of them may result in browser misinterpretations resulting in strange styling behavior (:only-child
, I am looking at you).
html
element. With other XML languages, however, this may come in useful if it's not clear what the root element might be.:first-child
, :only-child
and :last-child
pseudoclasses, but they select elements of a specific type—for example, if one used p:first-of-type
, it would select the first p
element, regardless of whether any other elements preceded it.The rest I explain below.
Four child-pseudoclasses allow you to select either a child other than the first or last of the parent element, or select elements in a pattern. These are:
What goes between the parentheses is either a number (to choose a specific child element) or a mathematical equation. The number is simple— 1
would select the first child element, the first child of its type, the last child, or the last of its type, depending on which of these pseudoclasses you used—in other words, they would be the equivalent of first-child
, first-of-type
, last-child
, and last-of-type
respectively. If you used the number 2
, it would get the second child element, the second of its type, the second-to-last element or the next-to-last of its type—assuming that those elements were there, of course.
An equation is a bit more complex: it takes the form of an±b
. In that equation, n
must remain n
, otherwise the equation won't work (I checked). Therefore, the two real variables here are a and b.
In the equation, a multiplies n. If a = 2, then every second child element (or child of its type) will be selected. If a = 3, then every third will be selected. If a = 1, you may as well omit a.
The variable b is added to or subtracted from an. If a = 1 (or is absent, which amounts to the same thing), b will have no effect if it is subtracted or adds only 1 to n (of course, if b = 0, it won't have any effect at all). If it adds two to an, then the first, first of its type, last, or last of its type (depending on which pseudo-class you're using) will be skipped; if b = 3, then the two first or two last will be skipped, and so on. The other way b can be used with an is to use the equation to set up a pattern: a to set the pattern's length (say every eight elements), b to decide where in that pattern a rule applies.
Below is a stylesheet using such selectors and a list that it styles.
ul
>li
>:nth-child(8n+1)</li
>li
>:nth-child(8n+2)</li
>li
>:nth-child(8n+3)</li
>li
>:nth-child(8n+4)</li
>li
>:nth-child(8n+5)</li
>li
>:nth-child(8n+6)</li
>li
>:nth-child(8n+7)</li
>li
>:nth-child(8n+8)</li
>li
>:nth-child(8n+1)</li
>li
>:nth-child(8n+2)</li
>li
>:nth-child(8n+3)</li
>li
>:nth-child(8n+4)</li
>li
>:nth-child(8n+5)</li
>li
>:nth-child(8n+6)</li
>li
>:nth-child(8n+7)</li
>li
>:nth-child(8n+8)</li
>ul
>The rather colourful result:
And yes, :nth-child(8n+2)
does indeed apply to the body
element as well; being the second child element of the html
element, it gets a white background and black text. I deliberately arranged the pattern that way to keep the page from looking hideous.
Olive background. Ick.
This is the only pseudo-class that's actually based on an attribute—specifically, the lang
attribute. This works much like the selector [lang]
and its variants, but also selects the child elements of a the matching element as well.
This pseudo-class is a bit more complicated because it takes the following form:
X
must not be blank; it must have a value—even if it is not a legitimate language code.
In the example below, I fiddled with the Lorem Ipsum
page to illustrate this. Since the text is not in any actual language, I used the fake language code x-Lorem
(x-
means an experimental language).
So behold the code (CSS rule highlighted and langage attributes highlighted):
Note that not only does the div
element with the lang
attribute get a border, but also its child elements, since they are assumed by the rule (and thus the browser) to be in the Lorem
language. That is the difference between [lang|="X"]
and :lang(X)
—the former would put a border around the div
element and ignore its children.
Before CSS 3, if we needed to exclude certain elements based on their attributes, names, etc., we would have to write a general rule including all elements based on its class, identity, attribute or name, then a more specific one based on whatever the element was/wasn't supposed to have. For example, if I wanted to select turn all p
elements without the attribute class
attribute red, I would have to turn all p
elements red, then code the exceptions. It was a very simple process—not!
Okay, I understand that usage of not
is almost 20 years old, but it seemed appropriate here.
This pseudoclass works on negation; it selects elements that don't have whatever is specified between the parentheses. Below is the selector that selects all elements that don't have the class
attribute:
:not()
Pseudoclass SelectorSince this was introduced in CSS 3, all browsers, even text-only browsers, support this pseudoclass—not.
While pseudo-classes control elements according to characteristics other than attributes, type, and ancestry, pseudo-elements tell a browser to select elements that don't exist—basically, they're added in by the stylesheet. The pseudo-elements are:
Two things to remember: First, these not universal to all modern browsers. Second, CSS 2 requires that the pseudo-element names be preceded with a single colon (:
), CSS 3 says they should be preceded by a double colon (::
). Browsers are more likely to support the single colon.
It is impossible to use (X)HTML to specify the first line of a paragraph. People may use different screen resolutions or may not even have their browser maximized. However, sometimes you do want to bring attention to the first line. That is what the first-line
pseudo-element is for. This rule depends entirely on the browser knowing where the first line ends.
The :first-letter
selects only the first letter in an element, allowing further styling of one's text. While you can specify the first letter using (X)HTML, this rule saves you some coding.
Below is a webpage that uses both pseudo-elements in its style sheet.
Below is the result:
These two pseudo-elements are used to put little something extra on either side of an element (which side is described by the pseudo-element).
Below is a page that uses both rules:
When you want to select paragraphs, the selector reads p
. When you want to select elements of the foreign
class, the selector reads .foreign
.
But what if you want to select paragraphs of the foreign class?
To understand this next part, you have to understand that every class selector, to the browser, looks like this:
.foreign
Remember the universal selector from earlier? When on its own, it selects everything, but now it selects everything with the foreign
class. Notice there is no space between *
and .foreign
(this is important).
To specify a specific type of element, replace *
with the element name you want. What this means is that the element must match in both name and class to be selected by the rule.
p
elements with "foreign" ClassDo note: The element name must always come first. That is how CSS works; it selects elements by element type first, then narrows down the selection by attributes and their values. The attributes, IDs, classes, and pseudo-classes may be in any order, but pseudo-elements must come at the end.
Below, I will demonstrate several combinations that can be made by this means:
class1and
class2
.class1.class2
p
and belong to class class1
p.class1
ul
and have the ID Navigation
ul#Navigation
Navigation. And, if used in an internal stylesheet, specifying the element type would indeed be redundant. But recall that the ID
Navigationmust be unique within the document, not within the website, and an external sheet can affect an infinite number of pages—and there could be as many elements with the ID
Navigationas there are pages. Some of these elements might be of the element type
ul
(in which case the rule would apply), some might of another type (and would therefore be excluded).q
, have the class whisper, and a
lang
attributeq.whisper[lang]
lang
attribute and may be of any language except English*.[lang]:not([lang|="en"])
These are just some of the combinations you can use to refine which elements are selected. There are only two combinations that you may not use: A combination of ID and ID and a combination of type and type. This is offset by the fact that each element may have only one ID and one type.
Selectors can be made more exclusive by specifying not just element, class, ID, attribute, or so on, but also specifying your desired elements' ancestors, parents, and siblings. In all cases of the following selectors, the last selector in the sequence is the subject of the rule.
For example, a selector could specify span
elements that are descendants of h2
elements. Below is the selector:
span
Elements With h2
AncestorsThe selector first specifies h2
elements, then tells the browser to look for a span
element within any h2
elements. It's important when using these selectors to name the elements from the outside in. The following selector is technically valid CSS, but is unlikely to select anything in a valid (X)HTML document.
h2
Elements With span
AncestorsIf the above selector does match something, it means you've nested an h2
element within a span
element, which you're not supposed to do, or you're abusing the del
and/or ins
elements.
It's important to remember that this selector specifies the descendant element, not the child element. This selector will match all span
elements nested within an h2
element, no matter what else they are nested in or how many layers of nesting there are.
This is universal to all browsers.
What if you wanted to specify only span
elements that had not just h2
ancestors, but h2
parents? A special symbol comes into play: >
.
span
Elements With h2
ParentsAs before, the selector first specifies h2
elements, then tells the browser to look for a span
element within any h2
elements—but this time, only to look as far as the children of the h2
elements. Grandchildren and so on are ignored.
This is not universal to all browsers.
This selector selects elements that follow other elements. The sign to signify this is +
. For example, if you wanted to target a paragraph that immediately followed a sixth-level header, the selector would be
p
With Immediately Preceding h6
SiblingIn this case, the browser look for an h6
element and then looks for a following p
element. Text between the two elements is not taken into account. However, if there is, say, a div
element between an h6
element and the next p
element, the rule would not come into effect.
CSS 3 introduced the ability to select an element by a preceding sibling that was not adjacent. The symbol for this is ~
.
p
With Preceding h6
SiblingIn this case, if there was a div
element between an h6
element and the next p
element, the rule would come into effect.
These are not universal to all browsers.
Below is a demonstration of how the above selectors work. Each instance of the words "span element" (or the plural thereof) is in a span
element.
Pictured below is the result:
The example back in Block Elements, which showed p
elements nested within del
and ins
elements can be simplified by these simple rules:
What this means is every p
element that is a descendant of a del
element gets a line through its text, and any p
element that is a descendant of an ins
element is underlined.
It also means you can get rid of the style
attributes used in the p
elements:
The result is identical to the example in Block Elements:
Now in the above examples, I specified ancestors by element name, but you can also specify them by attributes, class, ID, pseudo-class, or any combination of the above as seen in the Mix And Match
section. The only thing you can't use to specify ancestors, parents or siblings is a pseudo-element.
For example, in the stylesheet for this book, the first letter of the first paragraph of the chapter is large, and the text of the first paragraph flowed around it. But I didn't want the content of any following elements to be affected by it. So how do I select the next element?
This means Start with a
div
element with the class
value of chap_intro
, then find a child element that is a p
element and the first child, then find the following sibling of that p
element, whatsoever that sibling element might be.
div
elementclass
value of chap_intro,
p
elementp
element,If you've been using the JavaScript tools that I told you about back in the Prologue, you're likely to have seen some fairly complicated selectors. With what you've read in this chapter, you can now follow them and see just how those selectors work to pick out a specific element.
Tables are handled strangely in HTML: Browsers assume that every table
element has a tbody
element nested within, and all tr
elements are children of tbody
unless they are explicitely nested within thead
or tfoot
. This has far more effect on scripting, which is why I mention it again in The Document Object Model and DOM Manipulation. I explain why things are this way in Coding Shortcuts And Other Things.
XHTML—when read as an XML-based language—does not have this quirk. As with any element in an XML document, if the tags aren't there, neither is the element.
As each selector can have, at most, one rule (although you could have the same selector several times), a rule can have more than one selector. The symbol used to create a group of selectors is a comma, which tells the bowser to expect another selector.
For example, if you wanted all header elements to be centered, using one selector for each rule would look like this:
To save space and typing, you could also rewrite the above in this fashion:
You can join any number and any kind of selectors in this manner (my custom pagination stylesheet has a rule with no less than 257 selectors). Below is the result of adding an internal stylesheet with the above rule to the header elements example from Common Block Elements.
Just a few more things you should know.
One: while selecting elements solely by their name, class, ID, or attributes causes the top-to-bottom hierarchy of a stylesheet to be fairly straight forward, more complex selectors can cause things to get more complicated. So don't hesitate to make selectors more explicit to get the results that you want.
Two: The not()
pseudo-class can only handle simple selectors (that is, only a single attribute, class name, identity, etc). Each new exception will need another not()
pseudo-class appended to it. For example, if you wanted to select p
elements with neither class
or title
attributes, you would have to write out p:not([class]):not([title])
as the selector. Unfortunately, this does mean you cannot exclude elements by nesting.
Now that you know how selectors work, I can now explain what you can do with them. The next few chapters will be all about CSS properties, their permitted values, and how you can use them.