Style a parent element based on its number of children using CSS :has()

In CSS it’s possible to style elements based on the number of siblings they have by leveraging the nth-child selector.

But what if you want to style the parent element based on the number of children? Well, that where the CSS :has() selector comes into play.

~

# The code

If you’re just here for the code, here it is. You can also see it in action in the demo below.

/* At most 3 (3 or less, excluding 0) children */
ul:has(> :nth-child(-n+3):last-child) {
	outline: 1px solid red;
}

/* At most 3 (3 or less, including 0) children */
ul:not(:has(> :nth-child(3))) {
	outline: 1px solid red;
}

/* Exactly 5 children */
ul:has(> :nth-child(5):last-child) {
	outline: 1px solid blue;
}

/* At least 10 (10 or more) children */
ul:has(> :nth-child(10)) {
	outline: 1px solid green;
}

/* Between 7 and 9 children (boundaries inclusive) */
ul:has(> :nth-child(7)):has(> :nth-child(-n+9):last-child) {
	outline: 1px solid yellow;
}

If you want to know how it works, keep on reading 🙂

~

# The selectors

The pattern of each selector built here is this:

parent:has(> count-condition) {
	…
}
  • By using parent:has() we can select the parent element that meets a certain condition for its children.
  • By passing > into :has(), we target the parent’s direct children.
  • The count-condition is something we need to come up with for each type of selection we want to do. Similar to Quantity Queries, we’ll leverage :nth-child() for this.

☝️ Although the :has() selector is often called the parent selector, it is way more than that.

At most x children

By using :nth-child with a negative -n it’s possible to select the first x children. If one of those is also the very last child, you can detect if a parent has up to x children

/* At most 3 (3 or less, excluding 0) children */
ul:has(> :nth-child(-n+3):last-child) {
	outline: 1px solid red;
}

This selector excludes parents that have no children. This is fine in most cases – as any element that only contains text would be matched – but if you do want to include use this selector instead:

/* At most 3 (3 or less, including 0) children */
ul:not(:has(> :nth-child(3))) {
	outline: 1px solid red;
}

Exactly x children

To select item x from a set you can use :nth-child without any n indication. If that child is also the last child, you know there’s exactly x children in the parent

/* Exactly 5 children */
ul:has(> :nth-child(5):last-child) {
	outline: 1px solid blue;
}

At least x children

To select a parent with a least x children, being able to select child x in it is enough to determine that. No need for :last-child here.

/* At least 10 (10 or more) children */
ul:has(> :nth-child(10)) {
	outline: 1px solid green;
}

Between x and y children

To do a between selection, you can combine two :has() conditions together. The first one selects all elements that have x or more children, whereas the second one cuts off the range by only allowing elements that have no more than y children. Only elements that match both conditions will be mathed:

/* Between 7 and 9 children (boundaries inclusive) */
ul:has(> :nth-child(7)):has(> :nth-child(-n+9):last-child) {
	outline: 1px solid yellow;
}

~

# Demo

See the Pen Styling parent elements based on the number of children with CSS :has() by Bramus (@bramus) on CodePen.

~

# Browser Support

These selectors are supported by all browsers that have :has() support. At the time of writing this does not include Firefox.

Flipping on the experimental :has() support in Firefox doesn’t do the trick either. Its implementation is still experimental as it doesn’t support all types of selection yet. Relative Selector Parsing (i.e. a:has(> b)) is one of those features that’s not supported yet – Tracking bug: #1774588

~

# Spread the word

To help spread the contents of this post, feel free to retweet its announcement tweet:

~

Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Unless noted otherwise, the contents of this post are licensed under the Creative Commons Attribution 4.0 License and code samples are licensed under the MIT License

Join the Conversation

8 Comments

  1. Sigh, doesn’t appear to work in FireFox, even with the has option in about:config turned on.
    Is it me or can somebody reproduce it?

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.