The following is an extract from our book, HTML5 & CSS3 for the Real World, 2nd Edition, written by Alexis Goldstein, Louis Lazaris, and Estelle Weyl. Copies are sold in stores worldwide, or you can buy it in ebook form here.
Key Takeaways
- CSS3 selectors allow for precise targeting of elements on a webpage, expanding on the functionality of previous CSS versions. Relational and attribute selectors are key features of CSS3.
- Relational selectors target elements based on their relationship to another element within the markup. These include the descendant combinator (E F), child combinator (E > F), adjacent sibling or next sibling selector (E + F), and general sibling or following sibling selector (E ~ F).
- Attribute selectors in CSS3 allow for matching elements based on their attributes, with CSS3 expanding on CSS2’s attribute selectors by allowing for pattern matching. These include E[attr], E[attr=val], E[attr|=val], E[attr~=val], E[attr^=val], E[attr$=val], and E[attr*=val].
- CSS3 selectors are supported by all modern browsers, including IE9 and above. The use of these selectors can greatly enhance the efficiency and effectiveness of web design and development.
CSS3 Selectors
CSS selectors are at the heart of CSS. Without selectors to target elements on the page, the only way to modify the CSS properties of an element would be to use the element’s style
attribute and declare the styles inline, which is awkward and unmaintainable. So we use selectors. Originally, CSS allowed the matching of elements by type, class, and/or ID. This required adding class and ID attributes to our markup to create hooks and differentiates between elements of the same type. CSS2.1 added pseudo-elements, pseudo-classes, and combinators. With CSS3, we can target almost any element on the page with a wide range of selectors.
In the descriptions that follow, we’ll be including the selectors provided to us in earlier versions of CSS. They are included because, while we can use CSS3 selectors, selectors that predate CSS3 are also part of the CSS Selectors Level 3 specification and are still supported, as CSS Selectors Level 3 expands on them. Even for those selectors that have been around for quite some time, it’s worth going over them here, as there are some hidden gems in the old spec that few developers know. Note that all modern browsers, including IE9 and above, support all CSS3 selectors.
Relational Selectors
Relational selectors target elements based on their relationship to another element within the markup. All of these are supported since IE7+, and in all other major browsers:
Descendant combinator (E F
)
You should definitely be familiar with this one. The descendant selector targets any element F
that is a descendant (child, grandchild, great grandchild, and so on) of an element E
. For example, ol li
targets li
elements that are inside ordered lists. This would include li
elements in a ul
that’s nested in an ol
, which might not be what you want.
Child combinator (E > F
)
This selector matches any element F
that is a direct child of element E
—any further nested elements will be ignored.
Continuing the example, ol > li
would only
target li
elements directly inside the
ol
, and would omit those nested inside a
ul
.
Adjacent subling, or next sibling selector (E + F
)
This will match any element F
that shares
the same parent as E
, and comes
directly after E
in the markup. For example, li + li
will target all li
elements except the first li
in a given container.
General subling, or following sibling selector (E ~ F
)
This one’s a little trickier. It will match any element F
that shares the same parent as any E
and comes after it in the markup. So, h1 ~ h2
will match any h2
that follows an h1
, as long as they both share the same direct parent—that is, as long as the h2
is not nested in any other element.
Let’s look at a quick example:
<article>
<header>
<h1>Main title</h1>
<h2>This subtitle is matched </h2>
</header>
<p> blah, blah, blah …</p>
<h2>This is not matched by h1 ~ h2, but is by header ~ h2</h2>
<p> blah, blah, blah …</p>
</article>
The selector string h1 ~ h2
will match the first h2
, because both the h1
and h2
are children, or direct descendants, of the header
. The next h2
you’ll see in the code snippet doesn’t match, since its parent is article
, not header. It would, however, match header ~ h2
. Similarly, h2 ~ p
only matches the last paragraph, since the first paragraph precedes the h2
with which it shares the parent article.
Note: Why is there no “parent” selector?
You’ll notice that up to this point there has been no “parent” or “ancestor” selector, and there’s also no “preceding sibling” selector. The performance of the browser having to go backwards up the DOM tree, or recurse into sets of nested elements before deciding whether or not to apply a style, prevented the ability to have native “up the DOM tree” selectors.
jQuery included :has()
as an ancestral selector. This selector is being considered for CSS Selectors Level 4, but has yet to be implemented in any browser. If and when it is implemented, we will be able to use E:has(F)
to find E
that has F
as a descendant, E:has(> F)
, to find E
that has F
as a direct child, E:has(+ F)
, to find E
that directly precedes a sibling F
, and similar.
Looking through the stylesheet for The HTML5 Herald, you’ll see a number of places where we’ve used these selectors. For example, when determining the overall layout of the site, we want the three-column div
s to be floated left. To avoid this style being applied to any other div
s nested inside them, we use the child selector:
main > div {
float: left;
overflow: hidden;
}
As we add new styles to the site over the course of the next few chapters, you’ll be seeing a lot of these selector types.
Attribute Selector
CSS2 introduced several attribute selectors. These allow for matching elements based on their attributes. CSS3 expands upon those attribute selectors, allowing for some targeting based on pattern matching. CSS Selectors Level 4 adds a few more:
E[attr]
Matches any element E
that has the attribute attr
regardless of the attribute’s value. We made use of this back in Chapter 4 to style required inputs; input:required
works in the latest browsers, but input[required]
has the same effect and works in IE7 and IE8 as well.
E[attr=val]
Matches any element E
that has the attribute attr
with the exact value val
. While not new, it’s helpful in targeting form input types; for instance, targeting checkboxes with input[type=checkbox]
.
E[attr|=val]
Matches any element E
whose attribute attr
either has the value val
or begins with val-
. This is most commonly used for the lang
attribute. For example, p[lang|="en"]
would match any paragraph that has been defined as being in English whether it be UK or US English with <p lang="en-uk">
or <p lang="en-us">
.
Matches any element E
whose attribute attr
has within its value the full word val
, surrounded by whitespace. For example, .info[title~=more]
would match any element with the class info that had a title
attribute containing the word “more,” such as “Click here for more
information.”
E[attr^=val]
Matches any element E
whose attribute attr
starts with the value val
. In other words, the val
matches the beginning of the attribute value.
E[attr$=val]
Matches any element E
whose attribute attr
ends in val
. In other words, the val
matches the end of the attribute value.
E[attr*=val]
Matches any element E
whose attribute attr
matches val
anywhere within the attribute. It is similar to E[attr~=val]
, except the val
can be part of a word. Using the same example as before, .fakelink[title*=info] {}
would match any element with the class fakelink
that has a title
attribute containing the string info
, such as “Click here for more information.”
In these attribute selectors, the value of val
is case-sensitive for values that are case sensitive in HTML. For example, input[class^="btn"]
is case sensitive as class names are case sensitive, but input[type="checkbox"]
is not case sensitive, as the type
value is case-insensitive in HTML.
The value does not have to be quoted if the value is alphanumeric, with some exceptions. Empty strings, strings that begin with a number, two hyphens, and other quirks need to be quoted. Because of the exceptions, it’s a good idea to make a habit of always including quotes for those times when you do need them.
In CSS Selectors Level 4, we can have case insensitivity by including an i
before the closing bracket, E[attr*=val i]
.
Frequently Asked Questions on Relational and Attribute Selectors in CSS3
What is the difference between relational and attribute selectors in CSS3?
Relational selectors in CSS3 are used to select elements based on their relationship with other elements in the HTML document. For example, child, descendant, adjacent sibling, and general sibling selectors are all types of relational selectors. On the other hand, attribute selectors are used to select elements based on their attributes or attribute values. For instance, you can select all input elements with a type attribute of “text” using the attribute selector.
How do I use the child combinator in CSS3?
The child combinator in CSS3 is represented by the “>” symbol. It is used to select elements that are direct children of a specific element. For example, if you want to select all direct child div elements of a parent element with the class “parent”, you would write the CSS as follows:.parent > div {
/* CSS properties here */
}
Can I use multiple attribute selectors in CSS3?
Yes, you can use multiple attribute selectors in CSS3. This allows you to select elements that meet more than one attribute condition. For example, if you want to select all input elements with a type attribute of “text” and a name attribute of “username”, you would write the CSS as follows:input[type="text"][name="username"] {
/* CSS properties here */
}
What is the use of the adjacent sibling combinator in CSS3?
The adjacent sibling combinator in CSS3 is represented by the “+” symbol. It is used to select an element that is directly after another specific element, and both elements share the same parent. For example, if you want to select a div element that is directly after a p element, you would write the CSS as follows:p + div {
/* CSS properties here */
}
How do I select an element with a specific attribute value in CSS3?
To select an element with a specific attribute value in CSS3, you use the attribute selector with the attribute name and value in square brackets. For example, if you want to select all input elements with a type attribute of “text”, you would write the CSS as follows:input[type="text"] {
/* CSS properties here */
}
Can I combine relational and attribute selectors in CSS3?
Yes, you can combine relational and attribute selectors in CSS3. This allows you to select elements based on both their relationship with other elements and their attributes. For example, if you want to select all direct child input elements of a form element with a class of “form”, where the input elements have a type attribute of “text”, you would write the CSS as follows:form.form > input[type="text"] {
/* CSS properties here */
}
What is the general sibling combinator in CSS3?
The general sibling combinator in CSS3 is represented by the “~” symbol. It is used to select elements that are siblings of a specific element, regardless of their order in the HTML document. For example, if you want to select all div elements that are siblings of a p element, you would write the CSS as follows:p ~ div {
/* CSS properties here */
}
How do I select an element without a specific attribute in CSS3?
To select an element without a specific attribute in CSS3, you use the :not() pseudo-class with the attribute selector. For example, if you want to select all input elements that do not have a type attribute of “submit”, you would write the CSS as follows:input:not([type="submit"]) {
/* CSS properties here */
}
Can I use relational selectors with pseudo-classes in CSS3?
Yes, you can use relational selectors with pseudo-classes in CSS3. This allows you to select elements based on their relationship with other elements and their state. For example, if you want to select all direct child a elements of a nav element that are being hovered over, you would write the CSS as follows:nav > a:hover {
/* CSS properties here */
}
How do I select an element with a specific attribute that contains a certain value in CSS3?
To select an element with a specific attribute that contains a certain value in CSS3, you use the attribute selector with the attribute name and value in square brackets, and the *= operator. For example, if you want to select all a elements with an href attribute that contains “example”, you would write the CSS as follows:a[href*="example"] {
/* CSS properties here */
}
Alexis Goldstein first taught herself HTML while a high school student in the mid-1990s, and went on to get her degree in Computer Science from Columbia University. She runs her own software development and training company, aut faciam LLC. Before striking out on her own, Alexis spent seven years in Technology on Wall Street, where she worked in both the cash equity and equity derivative spaces at three major firms, and learned to love daily code reviews. She is a teacher and a co-organizer of Girl Develop It, and a very proud member of the NYC Resistor hackerspace in Brooklyn, NY.
Louis is a front-end developer, writer, and author who has been involved in the web dev industry since 2000. He blogs at Impressive Webs and curates Web Tools Weekly, a newsletter for front-end developers with a focus on tools.
Estelle Weyl is a front-end engineer from San Francisco who has been developing standards-based accessible websites since 1999. She also writes two technical blogs with millions of visitors. Her passion is teaching web development so you'll find her speaking about CSS3, HTML5, JavaScript, and mobile web development at conferences around the United States.