Mixing N-match notations in CSS

Week 185 was posted by Charanjit Chana on 2021-05-10.

When n-match notations first made their way to CSS, it was a game changer. No longer having write server side logic to determine if something was the first, last or nth child. Or worse still, having to resort to using JavaScript to apply the rules.

I would wager that most people stick to using :first-child and :last-child more than anything. With :nth-child and :nth-last-child you get a lot more flexibility and as described previously, these can be fairly complex and be applied every nth time.

It's great that this stuff just comes for free in CSS now. Thinking back, I would regularly write code trying to figure out the modulo of two numbers to see if it was either the first or last in a row and then using that to style it slightly differently. Maybe it would break to a new line or maybe it would be a different colour. Whatever it was, it was another line of code that needed to be maintained.

Why combine N-match notations?

CSS can't yet tell you how many children an element has, only what position each child is in. I would only recommend this method if you have a good idea of the maximum items. It won't be as effective if the count goes out of bounds, but by mixing your selectors, you can effectively get the functionality that's missing.

How do you combine :nth-child, :nth-last-child, :first-child, and :last-child selectors?

Simply specify two (or more) of these selectors against an element, without a space. Here's a simple example:

div:nth-child(3):nth-last-child(2)

This selects the third child, but only if it's the second last child. As I mentioned, this is a workaround for not being able to tell how many children an element has. There's already an :only-child selector so there's no need to write out any of the following:

(There are probably quite a few combinations that would get you here)

Let's look at a useful example, here we'll be figuring out how many trailing items there are. If there's 1, then it should take up all of the width available. Here we're selecting the 3rd child, but only if it's the last item.

.ex1 li:nth-child(3n+1):last-child {
  width: 100%;
}

What if there are two trailing items? The selectors get a little more complicated and we actually need two. One for the last item and one for the second to last item. First we need to get the 3rd child, but only if it's the second to last item as described. We also want the 3rd item in the second column, but only if it's the last item. In both cases, we can now set the width to the appropriate width.

.ex2 li:nth-child(3n+1):nth-last-child(2),
.ex2 li:nth-child(3n+2):last-child {
  width: calc(50% - 5px);
}

Finally, we have three full rows here. This list gets the same treatment as the two above, but because there are no trailing items, it just gets left alone.

It does take a bit of experimentation to get your head around how this all works, but for me it's far easier to let the CSS deal with these types of layout issues rather than having to cater for it in your markup. Feel free to play around with the example above over on Codepen.


Tags: css, development


Tweet WhatsApp Keep Upvote Digg Tumblr Pin Blogger LinkedIn Skype LiveJournal Like