The Simple Guide to Complex CSS Selectors

Stop guessing and start styling: In a world of complex CSS selectors, this guide makes finding the right one simple.

Published Categorized as Coding, CSS

Cascading Style Sheets, abbreviated as CSS, is a rule-based language for styling HTML documents.

With CSS, you can select DOM elements or groups of DOM elements in your HTML document and apply styles to them.

A single instance of this is called a rule. It consists of a selector with one or multiple declarations in the form of property/value pairs wrapped in curly brackets ({}).

For example, the CSS rule:

h1 {
  font-size: 42px;
}

Gives the inner text of all <h1> headings a font-size of 42 pixels.

It’s also an example of a rule with simple selectors. It targets one type of DOM element—headings with the <h1> tag—in a generic way and assumes a simple implementation context.

CSS selectors, however, can be much more sophisticated and specific than that. Especially since the introduction of CSS3, the most recent specification of the CSS standard, you can do complex CSS selection which previously was only possible with JavaScript and/or jQuery.

Table of Contents

This tutorial will teach you some of the most common complex CSS selectors—and how to make the most of them, including:

Descendant Selectors

In CSS, you can select one, multiple, or all descendant elements of an ancestor element.

Let’s suppose you’re working on a web page that has the following HTML markup:

<nav id="nav-menu">

  <ul class="nav-links">
    <li class="link">Link 1</li>
    <li class="link">Link 2</li>
    <li class="link">Link 3</li>
    <li class="link">Link 4</li>
  </ul>

  <ul class="nav-icons">
    <li class="icon">Icon 1</li>
    <li class="icon">Icon 2</li>
    <li class="icon">Icon 3</li>
  </ul>

  <div id="nav-toggle">
    <button id="button-toggle">Show more</button>
    <ul class="nav-toggle-links">
      <li class="link">Link 1</li>
      <li class="link">Link 2</li>
      <li class="link">Link 3</li>
    </ul>
  </div>

</nav>

With complex CSS selectors, you can create a number of patterns to target the DOM elements in this HTML markup differently depending on your needs.

Select All Descendants

You can select all descendants of an ancestor element with the ancestor descendant CSS combinator.

The CSS rule:

/* Selects all descendants of #nav-menu */

#nav-menu ul {
}

Will select all three <ul> elements (ul.nav-links, ul.nav-icons, and ul.nav-toggle-links) under #nav-menu.

Notice that, with this CSS combinator, the nesting of the descendant elements doesn’t matter. They can be nested directly under the ancestor or wrapped in any number of DOM elements. Either way, they will be selected.

Select Direct Descendants

You can select only direct descendants of an ancestor element with the ancestor > descendant CSS combinator.

The CSS rule:

/* Selects only direct descendants of #nav-menu */

#nav-menu > ul {
}

Will select only the first two <ul> elements (ul.nav-links and ul.nav-icons) in the HTML markup above.

With this CSS combinator, the nesting matters. Your selection will only include direct descendants of the ancestor and will exclude any DOM elements wrapped in other DOM elements.

Since ul.nav-toggle-links is not a direct descendant of the #nav-menu ancestor—it’s wrapped in a <div> element with an id of nav-toggle—it will be excluded.

Key Takeaways

SelectorTargetResult
ancestor descendantsAll descendants of ancestor, no matter the DOM nesting.Multiple elements
ancestor > descendantsOnly descendants of ancestor nested directly under it, not wrapped in other DOM elements.Multiple elements
Ancestor/descendant combinators

Child Selectors

In CSS, you can select one, multiple, or all child elements of a parent element. This is done with the nth-child pseudo-class.

Suppose you’re working on a CSS style for the following HTML markup:

<section id="blog">
  <article id="article-1">Article 1</article>
  <article id="article-2">Article 2</article>
  <article id="article-3">Article 3</article>
</section>

Select First Child

With the :first-child CSS pseudo-class, you can select the first child of a parent element.

The CSS rule:

/* Selects only the <article> that's the first child of #blog */

#blog article:first-child {
}

Selects the <article> element with an id of article-1 because it’s the first child of #blog. It also omits its peers with ids of article-2 and article-3 because they are, respectively, the second and the third child elements.

Select Last Child

With the :last-child CSS pseudo-class, you can select the last child of a parent element.

The CSS rule:

/* Selects only the <article> that's the last child of #blog */

#blog article:last-child {
}

Selects the <article> element with an id of article-3 because it’s the last child of #blog. It also omits its peers with ids of article-1 and article-2 because they are, respectively, the first and the third child elements.

Select Odd Children

With the :nth-child(odd) CSS pseudo-class, you can select the odd child elements of a parent element.

The CSS rule:

/* Selects only the odd <article> child elements of #blog */

#blog article:nth-child(odd) {
}

Selects the first, third, fifth, (…), n-th odd child elements of the #blog element.

Select Even Children

With the :nth-child(even) CSS pseudo-class, you can select the even child elements of a parent element.

The CSS rule:

/* Selects only the even <article> child elements of #blog */

#blog article:nth-child(even) {
}

Selects the second, fourth, sixth, (…), n-th even child elements of the #blog element.

Select nth Child

With the :nth-child(number) CSS pseudo-class, you can select the even child elements of a parent element.

The CSS rule:

/* Selects only the third <article> child elements of #blog */

#blog article:nth-child(3) {
}

Selects the third <article> that’s a child element of the DOM element with an id of blog.

Key Takeaways

SelectorTargetResult
:first-childThe first child element of a parent element.Single element
:last-childThe last child element of a parent element.Single element
:nth-child(even)The even child elements of a parent element.Multiple elements
:nth-child(odd)The odd child elements of a parent element.Multiple elements
:nth-child(number)The nth child element of a parent element.Single element
Parent/child pseudo-classes

Sibling Selectors

In CSS, you can select one, multiple, or all sibling elements of a given element.

Suppose you’re styling the following HTML markup:

<article id="article-1">
  <p class="intro">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
  <p>bi facilisis nulla dolor, scelerisque faucibus ex dapibus id.</p>
  <p>Interdum et malesuada fames ac ante ipsum primis in faucibus.</p>
</article>

All Siblings

With the element ~ siblings selector, you can select all siblings of a given DOM element.

The first element in the selector is for the main element and the second element/group of elements is/are its siblings under the same parent.

The CSS rule:

/* Select all sibling paragraphs of p.intro */

p.intro ~ p {
}

Selects the two sibling paragraphs of p.intro, meaning the second and third paragraphs at lines three and four.

Adjacent Sibling

With the element + siblings selector, you can select only the adjacent sibling of a given DOM element.

The first element in the selector is for the main element and the second element is the sibling under the same parent element that immediately follows it.

The CSS rule:

/* Select the adjacent sibling paragraph immediately after p.intro */

p.intro + p {
}

Selects the adjacent sibling paragraph of p.intro, meaning the second paragraphs at line three that immediately follows it in the HTML markup.

Key Takeaways

SelectorTargetResult
element ~ siblingsAll siblings of a given element within a parent element in the DOM.Multiple elements
element + siblingThe adjacent sibling of a given element within a parent element in the DOM.Single element
Sibling combinators

Attribute Selectors

In CSS, you can select one, multiple, or all elements based on their HTML attributes. This includes default attributes, such as the href attribute of <a> elements, as well as any custom attributes specific to your HTML document’s markup.

Presence of Attribute

To select one or multiple DOM elements based on whether they have an HTML attribute or not, use the [name] selector, where name is the name of the attribute.

For example, in the CSS stylesheet:

/* Select all DOM elements with an "href" attribute */

[href] {
}

/* Select only <a> elements with an "href" attribute */

a[href] {
}

The [href] rule selects all DOM elements with an href attribute, whereas the a[href] rule selects all <a> elements with an href attribute.

Value of Attribute

With attribute selectors, you can get really specific about which DOM elements to target.

Not long ago, I wrote about this in detail in a post called “The Guide to Custom Attribute Selectors in CSS.” Check out that post if you want to learn the nuts and bolts of these CSS selectors, or read on for an overview.

Exact Match

To select one or multiple DOM elements based on the presence and the exact value of an HTML attribute, use the [name="value"] selector, where name is the name of the attribute and value is its value.

For example, the CSS rule:

/* Select links set to open in a new window */

a[target="_blank"] {
}

Selects only <a> elements whose target attribute is set to “_blank.”

Containing a Value

The [name*="value"] selector lets you select DOM elements that have the given custom attribute and whose value contains a given value, whether by itself or within a word or number.

For example, the CSS rule:

/* Select internal links only */

a[href*="makersaid.com"] {
}

Selects only <a> hyperlinks whose href attribute contains “makersaid.com.”

Starting With a Value

The [name^="value"] selector lets you select DOM elements that have the given custom attribute and whose value starts with a given value.

For example, in the CSS stylesheet:

/* Select anchor links only */

a[href^="#"] {
}

/* Select external links only */

a[href^="http"] {
}

The first CSS selector is for anchor links since the value of their href attributes starts with a hash (#), and the second CSS selector is for external links since their href attributes always start with “http.”

Ending With a Value

The [name$="value"] selector lets you select DOM elements that have the given custom attribute and whose value ends with a given word.

For example, the CSS selector:

/* Select links to .org domain names only */

a[href$=".org"] {
}

Selects all <a> hyperlinks whose href attributes contain .org domain names.

Key Takeaways

SelectorTargetResult
[attribute]All DOM elements that have a given attribute.Multiple elements
[attribute="value"]All DOM elements that have a given attribute with this exact value.Multiple elements
[attribute^="value"]All DOM elements that have a given attribute that starts with this value.Multiple elements
[attribute$="value"]All DOM elements that have a given attribute that ends with this value.Multiple elements
Attribute selectors
Image courtesy of Kelly Sikkema /Unsplash

Leave a comment

Your email address will not be published.