I’ve often wondered why this doesn’t exist already as I am not the first to think this would be useful. Perhaps there’s some implementation technicalities that I’ve not considered (most likely!).
On occasion you may have a list of similar elements followed by an element which is not so similar. If you want to style the last element of your “similar” elements you can’t use :last-child. Here’s a really simple example. In this example, imagine you want to remove the border of the last “thing”. You can’t use :last-child because that matches the <button>.
Of course there are many workarounds for this limitation. Notably the following spring to mind:
“Add another class to the last item”
“wrap the elements which are similar in some other element (perhaps an
(un)ordered list for semantics) and then use last-child”
While these are of course perfectly valid, and in some situations will actually be a better or (arguably) more semantic solution, sometimes it’s extra hassle that could easily be avoided if we had something like :last-of-class(‘thing’)
Are there issues with this proposal that I might have not considered?
The spec already covers this, via :nth-child(). You can pass a selector argument to specialize the counting to only cover things matching that selector. This hasn’t been implemented by anyone yet, to my knowledge.
If the selector you want to use is just a type selector, :nth-of-type() works. In that JSBin, for example, a selector like div:last-of-type would select the last “thing” as expected.
+1 Yep, :last-of-type is probably what’s needed. Note also, @Wills, that nth-last-of-type() can be used to count back from the final instance of that type. So, for example, p:nth-last-of-type(2) would match each instance of a penultimate paragraph.
There’s very little you can’t do with the extant CSS3 selectors, in my experience. Especially since you can concatenate them. Eg. p:nth-child(even):nth-last-of-type(3) would match any even occurences of a p if they are also third last in a succession of ps. Not that you’d need that particular one very often…
@heydonworks I’m aware of nth-of-type and last-of-type but using those results in a brittle solution which doesn’t actually select the element for the reasons the element is being targeted (in this case). Just because the element is the second-to-last child at the moment, doesn’t mean it will always be. It’s just a happy coincidence of the provided example. The same applies for if I’d have used last-of-type. If I suddenly needed to change the <button> to a <div> in my HTML, I’d have to go and find and alter the CSS for the (unrelated) element and update the n value for the nth-last-of-type.
I wasn’t suggesting you use nth-last-of-type. All you need is last-of-type as @tabatkins suggested. I was just mentioning nth-last-of-type as an additional tool for more complex scenarios. You say ‘brittle’, I say ‘specific’ Naturally, you’ll want to be as unspecific as you can get away with. Just using an extreme example to show what’s possible in current implementations.
My point was that using last-of-type in some situations just coincidentally happens to select the right element.
I said this was brittle as if you were to add another element of the same type then the last-of-type selector would no longer match the desired element. Whereas if last-child(.my-class) were available it would (assuming the new element didn’t also have that class of course…). Usually in these situations where I need to select these sorts of elements my though process is something like “I need to select the last .my-class element and remove the border”. Element type doesn’t come into it.
Basically I’m saying type selectors are often best avoided as they are too broad, as demonstrated by the above example ;).