And the container controls the variables of :nth-child():
.container {
--A: ;
--B: ;
}
.container > div {
/* primarily based on the values of --A and --B change the background worth */
background: ??;
}
I'm not saying that this construction is obligatory for the implementation. I simply thought-about a easy one to maintain issues simple to observe.
:nth-child(B)
Let’s begin with the only case, a selector that selects just one factor:
div:nth-child(5) { }
I don’t suppose I want to clarify what this selector does. The 5 is nothing however the index of the chosen factor. So, if B is the same as the index of the factor, that factor is chosen.
We will translate this into the next CSS code:
.container {
--B: 5;
}
.container div {
background: if(model(sibling-index() = --B): pink);
}
Is that this a sound CSS code?!
Sure, it’s legitimate, and it really works!
I'm utilizing the brand new if() syntax that permits me to outline a situation inside model(). If that situation is true, the background shade is about to pink. In any other case, nothing occurs.
We will even have an if/else:
.container {
--B: 5;
}
.container div {
background: if(model(sibling-index() = --B): pink; else: lightblue);
}
The if() syntax just isn't that advanced. In our case, we solely have one situation, so you possibly can see it as follows:
.container div {
background:
if(model( situation ): ;
else: );
}
The tough half is the best way to outline the situation inside model(). I wrote a small publish explaining this half, so do your self a favor and go learn it earlier than we proceed: “The Hidden Trick of Type Queries and if().” It’s a fast studying with essential particulars that helps you higher perceive how if() works. From there, you'll discover that our situation might be written a number of methods which might be all legitimate:
.container div {
background: if(model(sibling-index() = --B): pink);
background: if(model(sibling-index() = var(--B)): pink);
background: if(model(var(--B) = sibling-index()): pink);
background: if(model(--B = sibling-index()): pink);
}
We've our first implementation! You possibly can simply apply it to any property as properly:
.container {
--B: 5;
}
.container div {
background: if(model(sibling-index() = --B): pink; else: lightblue);
shade: if(model(sibling-index() = --B): white);
}
The code seems to be a bit redundant, which might be one of many drawbacks of this methodology, however it’s nonetheless cool to implement the selector and be capable of regulate the worth of --B on the fly. Don’t overlook that our aim is to be taught new methods, and you have already got two of them in your pocket (sibling-index() and if()).
Right here is an interactive demo the place you possibly can regulate the worth of --B and see the modifications:
:nth-child(n + B)
Let’s transfer to our subsequent selector. It selects multiple factor.
div:nth-child(n + 5) { }
Suppose for a second about the best way to implement such a selector. It’s nearly the identical because the earlier one.
You bought it? I hope so!
.container {
--B: 5;
}
.container div {
background: if(model(sibling-index() >= --B): pink; else: lightblue);
}
If the index of the factor is larger than or equal to the worth of --B, the factor is chosen. So simple as that!
:nth-child(-n + B)
What about this one? Straightforward, proper? We merely use <= as an alternative of >=!
.container {
--B: 5;
}
.container div {
background: if(model(sibling-index() <= --B): pink; else: lightblue);
}
We will additionally simply implement a variety choice, which is the mixture of each selectors:
/* choose any factor within the vary [X Y] */
div:nth-child(n + X):nth-child(-n + Y) {
background: pink;
}
It interprets into:
.container {
--X: ;
--Y: ;
}
.container div {
background: if(model(--X <= sibling-index() <= --Y): pink);
}
The code must be self-explanatory. It’s much more intuitive than the :nth-child() notation, which requires a couple of minutes of deciphering if you're not used to it.
:nth-child(An)
Now let’s take care of the A argument. For instance, the next selector:
div:nth-child(3n) { }
…selects the third, sixth, ninth, and so on. parts. Seen in another way, the index of the factor must be a a number of of 3. To do such testing, we are able to use the mod() operate. If mod(index, 3) returns 0, it means the rest of the division of index by 3 is the same as 0, therefore, it’s a a number of of 3.
.container {
--A: 3;
}
.container div {
background: if(model(mod(sibling-index(), var(--A)) = 0): pink);
}
It really works! One other selector with a easy implementation.
We will establish two particular instances. When --A is the same as 1, we now have :nth-child(n), which selects all the weather and when it’s equal to 2, we now have :nth-child(2n) which can be :nth-child(even).
Whereas this works high quality, there's a small gotcha. When A is a damaging worth, the selector ought to choose nothing which is logical as all of the indexes are constructive, however in the event you attempt utilizing damaging values with my implementation, some parts nonetheless get chosen which is unsuitable.
The mod() operate works with damaging numbers and might nonetheless return 0 in such instances, so to be extra correct, we must always check the signal of A.
.container {
--A: 3;
}
.container div {
background:
if(model( (mod(sibling-index(), var(--A)) = 0) and (var(--A) > 0): pink);
}
See that? I merely added one other situation inside model() utilizing the and key phrase. The syntax of if() might sound complicated at first look, however on the finish it’s the identical as some other language: a bunch of situations outlined inside model(). You possibly can have as many as you need mixed with and and or.
Now, our choice is extra exact.
:nth-child(An + B)
Now let’s mix all of the methods we discovered to date to implement the generic type of :nth-child(). On this case, the index is the same as An + B, and we are able to categorical n like this:
n = (index - B)/A
n must be a constructive integer (zero included). For the constructive half, we are able to use:
(index - B)/A >= 0
For the integer half, we'd like to ensure index - B is a a number of of A, and for this, we use mod():
mod(index - B, A) = 0
We translate this into CSS to get the next:
.container {
--A: 3;
--B: 5;
}
.container div {
background:
if(model( (mod(sibling-index() - var(--B), var(--A)) = 0)
and (calc((sibling-index() - var(--B))/var(--A)) >= 0)
): pink);
}
We're nearly good aside from the case when --A is the same as 0. In that case, the choice is solely unsuitable. The mod() ends in NaN since its second argument is the same as 0, and this can mess with the situation. Really, that situation just isn't meant to work with --A equal to 0.
We both take into account that this implementation is just legitimate for a price of --A completely different from 0 (which might be what we would like) or we attempt to discover a resolution to incorporate that case.
We're right here to be taught and uncover new stuff, so let’s attempt one thing else. There are most likely loads of methods to repair the case of 0, however right here is my thought:
.container {
--A: 3;
--B: 5;
}
.container div {
--n: calc((sibling-index() - var(--B))/var(--A));
--g: if(model(--A = 0):
calc(signal(sibling-index() - var(--B)) + 1);
else:
calc(signal(var(--n) + 1) + mod(var(--n),1))
);
background: if(model(--g = 1): pink);
}
How does it work? Effectively, this will likely be your homework!
As you possibly can see, I've launched a brand new variable that must be equal to 1 if the factor is chosen by :nth-child(An + B). Attempt to dissect the code to know the way it works. When you nonetheless battle, verify the next publish: “Dynamic nth-child() utilizing sibling-index() andif().”
And right here is the ultimate interactive with the whole implementation of :nth-child(An + B):
We will simply get all of the earlier selectors by merely adjusting the variables:

:nth-child(7)
:nth-child(n + 10)
:nth-child(-n + 10)
:nth-child(3n)Conclusion
I hope you loved this small train. It was a very good alternative to discover the brand new if() function, and the :nth-child() selector was the right candidate for this. In spite of everything, selectors are nothing however a set of situations to filter parts and choose the wanted ones.
What about :nth-last-child()? If you're up for one more problem, attempt to see how one can replace the earlier implementation to make it work with :nth-last-child(). (Trace: you might must depend on sibling-count().)








