CSS Selectors: Combinators

Share this article

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.

cssmasterthumb

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.

SelectorsCombinators

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.

DescendantCombinator

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.

DescendentCombinator2

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.

ChildCombinator

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.

AdjacentSibling1

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.

AdjacentSibling3

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.

GeneralSiblingCombinator

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

element, you would write it as “div > p”. This will apply the CSS styles only to the

elements that are direct children of the

element, not to those that are nested deeper.

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

element, while “div p” selects all

elements within the

element, regardless of how deeply they are nested.

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, you would write it as “div + p”. This will apply the CSS styles only to the

element that directly follows the

element.

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 and is also directly following another

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

element.

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

element by writing “div p”. You can also use the child combinator to style only the direct children of a
element by writing “div > p”. By combining different combinators, you can create very specific selectors that target exactly the elements you want to style.

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

element.

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

element.
Tiffany BrownTiffany Brown
View Author

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.

book excerptCSScss selectorsCSS3learn-advanced-css
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week