Search code examples
csscss-selectorspseudo-class

Unexpected behaviour from :nth-of-type(n+1)


I'm an avid user of the x-of-type family of CSS pseudo-classes:

  • :first-of-type
  • :last-of-type
  • :nth-of-type
  • :nth-last-of-type

I am usually fairly adept at ensuring that any series of similar elements (list items etc.) displays exactly as I wish it to.

In the last hour, however, I have been stuck on how to achieve the following result with a single style declaration:

  • Item 1 has a border-bottom
  • Item 2 has a border-bottom
  • Item 3 has a border-bottom
  • Item 4 (the last item) has no border-bottom

I have achieved what I need, using:

.item {
border-bottom:6px solid rgb(227,227,227);
}

.item:last-of-type {
border-bottom:none;
}

but for the purposes of brevity, I'd still prefer to achieve the same result with a single declaration.

Question:

Why won't

.item:nth-of-type(n-1) {
    border-bottom:6px solid rgb(227,227,227);
    }

or

.item:nth-last-of-type(n+1) {
    border-bottom:6px solid rgb(227,227,227);
    }

work?

Is it because n is simply an infinite list of numbers, including numbers before and after the number of targeted elements on the page?

If so, how can I declare "Everything but the last item" in a single declaration?

(And apologies in advance, if it's something really obvious and I've just failed to notice it...)


Added...

Here is the HTML I'm working with:

<aside>
<img src="" title="" alt="" />
<span class="something-else">Blah</span>
<span class="item">Item Details</span>

<img src="" title="" alt="" />
<span class="something-else">Blah</span>
<span class="item">Item Details</span>

<img src="" title="" alt="" />
<span class="something-else">Blah</span>
<span class="item">Item Details</span>

<img src="" title="" alt="" />
<span class="something-else">Blah</span>
<span class="item">Item Details</span>
</aside>

Solution

  • Is it because n is simply an infinite list of numbers, including numbers before and after the number of targeted elements on the page?

    Yes, that's why :nth-of-type(n-1) appears to match every element: n counts an infinite number of times. So the last of type will still match, when n is 1 plus the total number of children of that element type. In other words, the expression n-b for any b (or n+b for b <= 1) is equivalent to n (itself n-0), which is a guaranteed match.

    :nth-last-of-type(n+1) is close, but the reason that doesn't do what you want is because n starts counting from zero, so when n is zero, n+1 matches the last of type.

    If so, how can I declare "Everything but the last item" in a single declaration?

    You have two ways. One that you were close to is :nth-last-of-type(n+2). The other is the much clearer :not(:last-of-type).