Key Takeaways
- CSS selectors match rules to elements, with the Selectors Level 3 and Level 4 specifications introducing several new selectors. These include new attribute selectors and combinators, and a range of new pseudo-classes.
- Combinators are character sequences that express a relationship between the selectors on either side of it. They include the descendant combinator (whitespace), child combinator (>), adjacent sibling combinator (+), and general sibling combinator (~).
- The descendant combinator selects all elements that are descendants of a specified element, the child combinator selects all elements that are direct children of a specified element, the adjacent sibling combinator selects all elements that are the next siblings of a specified element, and the general sibling combinator selects all elements that are siblings of a specified element.
- CSS combinators can be combined with pseudo-classes and attribute selectors, and they can be used to style nested elements. However, they do not have any specificity themselves; they only help to determine the specificity of a selector by defining the relationship between elements.
CSS rules are matched to elements with selectors. There are a number of ways to do this, and you’re probably familiar with most of them. Element type, class name, ID, and attribute selectors are all well-supported CSS selectors and widely used.
The Selectors Level 3 and Level 4 specifications introduced several new selectors. In some cases, these are new variations of existing types. In other cases, they are new features of the language.
In this chapter, we’ll look at the current browser landscape for CSS selectors, with a focus on newer selectors. This includes new attribute selectors and combinators, and a range of new pseudo-classes. In the section Choosing Selectors Wisely, we look at the concept of specificity.
This chapter stops short of being a comprehensive look at all selectors―that could be a book unto itself. Instead, we’ll focus on selectors with good browser support that are likely to be useful in your current work. Some material may be old hat, but it’s included for context.
Tip: Browser Coverage for Selectors
A comprehensive look at the current state of browser support for selectors can be found at CSS4-Selectors.
The following is an extract from our book, CSS Master, written by Tiffany B. Brown. Copies are sold in stores worldwide, or you can buy it in ebook form here.
Combinators
Combinators are character sequences that express a relationship between the selectors on either side of it. Using a combinator creates what’s known as a complex selector. Complex selectors can, in some cases, be the most concise way to define styles.
You should be familiar with most of these combinators:
-
descendant combinator, or whitespace character
-
child combinator, or
>
-
adjacent sibling combinator, or
+
-
general sibling combinator, or
~
Let’s illustrate each of these combinators. We’ll use them to add styles to the HTML form shown below.
This form was created using the following chunk of HTML:
<form method="GET" action="/processor">
<h1>Buy Tickets to the Web Developer Gala</h1>
<p>Tickets are $10 each. Dinner packages are an extra $5. All fields are required.</p>
<fieldset>
<legend>Tickets and Add-ons</legend>
<p>
<label for="quantity">Number of Tickets</label>
<span class="help">Limit 8</span>
<input type="number" value="1" name="quantity" id="quantity" step="1" min="1" max="8">
</p>
<p>
<label for="quantity">Dinner Packages</label>
<span class="help">Serves 2</span>
<input type="number" value="1" name="quantity" id="quantity" step="1" min="1" max="8">
</p>
</fieldset>
<fieldset>
<legend>Payment</legend>
<p>
<label for="ccn">Credit card number</label>
<span class="help">No spaces or dashes, please.</span>
<input type="text" id="ccn" name="ccn" placeholder="372000000000008" maxlength="16" size="16">
</p>
<p>
<label for="expiration">Expiration date</label>
<span class="help"><abbr title="Two-digit month">MM</abbr>/<abbr title="Four-digit Year">MM</abbr>YYYY</span>
<input type="text" id="expiration" name="expiration" placeholder="01/2018" maxlength="7" size="7">
</p>
</fieldset>
<fieldset>
<legend>Billing Address</legend>
<p>
<label for="name">Name</label>
<input type="text" id="name" name="name" placeholder="ex: John Q. Public" size="40">
</p>
<p>
<label for="street_address">Street Address</label>
<input type="text" id="name" name="name" placeholder="ex: 12345 Main Street, Apt 23" size="40">
</p>
<p>
<label for="city">City</label>
<input type="text" id="city" name="city" placeholder="ex: Anytown">
</p>
<p>
<label for="state">State</label>
<input type="text" id="state" name="state" placeholder="CA" maxlength="2" pattern="[A-W]{2}" size="2">
</p>
<p>
<label for="zip">ZIP</label>
<input type="text" id="zip" name="zip" placeholder="12345" maxlength="5" pattern="0-9{5}" size="5">
</p>
</fieldset>
<button type="submit">Buy Tickets!</button>
</form>
The Descendant Combinator
You’re probably quite familiar with the descendant combinator. It’s been around since the early days of CSS (though it was without a type name until CSS2.1). It’s widely used and widely supported.
The descendant combinator is just a whitespace character. It separates the parent selector from its descendant, following the pattern A B, where B is an element contained by A. Let’s add some CSS to our markup from above and see how this works:
form h1 {
color: #009;
}
We’ve just changed the color of our form title, the result of which can be seen below.
Let’s add some more CSS, this time to increase the size of our pricing message (“Tickets are $10 each”):
form p {
font-size: 22px;
}
There’s a problem with this selector, however, as you can see below. We’ve actually increased the size of the text in all of our form’s paragraphs, which isn’t what we want. How can we fix this? Let’s try the child combinator.
The Child Combinator
In contrast to the descendant combinator, the child combinator (>) selects only the immediate children of an element. It follows the pattern A > B, matching any element B where A is the immediate ancestor.
If elements were people, to use an analogy, the child combinator would match the child of the mother element. But the descendant combinator would also match her grandchildren, and great-grandchildren. Let’s modify our previous selector to use the child combinator:
form > p {
font-size: 22px;
}
Now only the direct children of article
are affected, as shown below.
The Adjacent Sibling Combinator
With the adjacent sibling combinator (+
), we can select elements that follow each other and have the same parent. It follows the pattern A + B. Styles will be applied to B elements that are immediately preceded by A elements.
Let’s go back to our example. Notice that our labels and inputs sit next to each other. That means we can use the adjacent sibling combinator to make them sit on separate lines:
label + input {
display: block;
clear: both;
}
You can see the results below.
Let’s look at another example that combines the universal selector (*) with a type selector:
* + fieldset {
margin: 5em 0;
}
This example adds a 5em
margin to the top and bottom of every fieldset
element, shown below. Since we’re using the universal selector, there’s no need to worry about whether the previous element is another fieldset
or p
element.
Note: More Uses of the Adjacent Sibling Selector
Heydon Pickering explores more clever uses of the adjacent sibling selector in his article “Axiomatic CSS and Lobotomized Owls.”
What if we want to style a sibling element that isn’t adjacent to another, as with our Number of Tickets field? In this case, we can use the general sibling combinator.
The General Sibling Combinator
With the general sibling combinator―a tilde―we can select elements that share the same parent without considering whether they’re adjacent. Given the pattern A ~ B, this selector matches all B elements that are preceded by an A element, whether or not they’re adjacent.
Let’s look at the Number of Tickets field again. Its markup looks like this:
<p>
<label for="quantity">Number of Tickets</label>
<span class="help">Limit 8</span>
<input type="number" value="1" name="quantity" id="quantity" step="1" min="1" max="8">
</p>
Our input
element follows the label
element, but there is a span
element in between. Since a span
element sits between input
and label
, the adjacent sibling combinator will fail to work here. Let’s change our adjacent sibling combinator to a general sibling combinator:
label ~ input {
display: block;
}
Now all of our input
elements sit on a separate line from their label
elements, as seen below.
Using the general sibling combinator is the most handy when you lack full control over the markup. Otherwise, you’d be better off adjusting your markup to add a class name. Keep in mind that the general sibling combinator may create some unintended side effects in a large code base, so use with care.
Frequently Asked Questions (FAQs) about CSS Selectors and Combinators
What are the different types of CSS combinators and how do they function?
CSS combinators are used to explain the relationship between two or more CSS selectors. There are four types of combinators in CSS: descendant combinator (space), child combinator (greater than symbol >), adjacent sibling combinator (plus symbol +), and general sibling combinator (tilde symbol ~). The descendant combinator selects all elements that are descendants of a specified element. The child combinator selects all elements that are direct children of a specified element. The adjacent sibling combinator selects all elements that are the next siblings of a specified element. The general sibling combinator selects all elements that are siblings of a specified element.
How do I use the child combinator in CSS?
The child combinator in CSS 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
elements that are direct children of a
elements that are direct children of the
What is the difference between a child combinator and a descendant combinator?
The main difference between a child combinator and a descendant combinator lies in their specificity. A child combinator (>) selects only the direct children of a specific element, while a descendant combinator (space) selects all descendants (children, grandchildren, etc.) of a specific element. For example, “div > p” selects only the
elements that are direct children of a
elements within the
How does the adjacent sibling combinator work in CSS?
The adjacent sibling combinator in CSS 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
element that directly follows a
element that directly follows the
Can I combine multiple CSS combinators in a single rule?
Yes, you can combine multiple CSS combinators in a single rule to create more specific and complex selectors. For example, you can combine the child combinator and the adjacent sibling combinator to select an element that is both a direct child and an adjacent sibling of specific elements. The rule “div > p + p” will select a
element that is a direct child of a
element.
What is the general sibling combinator in CSS?
The general sibling combinator in CSS is represented by the “~” symbol. It is used to select elements that are siblings of a specific element. Unlike the adjacent sibling combinator, the general sibling combinator selects all elements that are siblings of a specific element, not just the one that directly follows it. For example, “div ~ p” will select all
elements that are siblings of a
How can I use CSS combinators to style nested elements?
CSS combinators can be very useful for styling nested elements. For example, you can use the descendant combinator to style all
elements within a
Can I use CSS combinators with pseudo-classes?
Yes, you can use CSS combinators with pseudo-classes. For example, you can use the child combinator with the :first-child pseudo-class to select the first child of a specific element. The rule “div > p:first-child” will select the first
element that is a direct child of a
What is the specificity of CSS combinators?
CSS combinators themselves do not have any specificity. However, they help to determine the specificity of a selector by defining the relationship between elements. The specificity of a selector is calculated based on the number of ID selectors, class selectors, and type selectors it contains. A selector with more specific selectors will override a selector with less specific selectors.
Can I use CSS combinators with attribute selectors?
Yes, you can use CSS combinators with attribute selectors. For example, you can use the child combinator with an attribute selector to select elements that have a specific attribute and are direct children of a specific element. The rule “div > p[title]” will select all
elements that have a title attribute and are direct children of a
Tiffany B. Brown is a freelance web developer and technical writer based in Los Angeles. Brown offers web development and consulting services to larger agencies and small businesses. A former member of the Opera Software developer relations team, Brown is also co-author of SitePoint's JumpStart HTML5 book. She sporadically writes about web development technology on her blog. You can follow her on Twitter at @webinista.