CSS :nth-of-class selector

The Problem

One thing that bothers me with CSS :nth-of-type/:nth-child selectors is that you can’t combine them with CSS classes. The selector below for example won’t work as you’d first expect it to work:

.bar:nth-child(2) {
  color: red;

No, the selector above won’t color the second .bar element red, something I had somehow expected it to do. What the selector will target instead, is an element that is both .bar and :nth-child(2):

See the Pen .class:nth-of-type by Bramus (@bramus) on CodePen.


Enter :nth-child(An+B [of S]?)

To solve my problem, I’d be needing something like a :nth-of-class selector. Unfortunately no such selector exists nor is it currently proposed. What is proposed though, in the upcoming CSS Level 4 Selectors specification (aka “not CSS4” 😜), is an extension to the nth-child/nth-last-child pseudo selectors: the ability to add an optional of S part into those selectors.

The :nth-child(An+B [of S]?) pseudo-class notation represents elements that are among An+Bth elements from the list composed of their inclusive siblings that match the selector list S, which is a <complex-real-selector-list>. If S is omitted, it defaults to *|*.

Thanks to this of S extension, we can select all children that also match the given selector-list S. By filling in the An+B clause, we can then select the An+Bth from that pre-filtered set of children.

All together, our wanted :nth-of-classselector becomes a reality:

:nth-child(2 of .bar) {
  color: red;

In words, the selector reads: “Within its parent, select all article children that are also matched by .bar. From that prefiltered set, give me the second item.”

💡 Note that the .bar selector used here is pretty simply as a value for S. S accepts a comma-separated list of <complex-real-selector>s which roughly translates to just about any selector as long as it’s not a relative one or one that targets a pseudo-element. That means that, for example, :not(.foo) and section > .bar are also allowed values for S.



Here’s a pen with the result:

See the Pen .class:nth-of-type by Bramus (@bramus) on CodePen.


Browser Support

If you’re using Firefox or Chrome you’ll see that the demo above is broken, as browser support for it is bad. Only Safari supports it at the time of writing.

UPDATE 2023.01.01 Chrome Canary 111.0.5530.0 comes with experimental support for :nth-child(An+B [of S]?). To try it, flip on the “Experimental Web Platform Features” feature flag through chrome://flags

Other browser that currently don’t support it have meta-issues to implement CSS Level 4 selectors:

Please vote on those bugs mentioned above if you want those features to land in the browsers.

🗳 By massively voting on browser bugs we can “tell” a browser vendor that we’d like to see a certain feature land. Go forth and vote.


Did this help you out? Like what you see?
Thank me with a coffee.

I don\'t do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

BuymeaCoffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

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


    1. That still selects the first .bar (as it happens to also be the 2nd element in the list)

  1. This is a workaround but since lists or rows are usually rendered using .map or by iterating, I added ‘even’ and ‘odd’ class names to every other element and then can target them in css without :nth-child.

    pseudo-react example:
    DIV className={‘my-class ‘ + (i%2 === 0 ? ‘even’ : ‘odd’)} /DIV

    .my-class.odd {
    background: grey

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.