This is largely a matter of semantics.
Generally, you use :first-child/:first-of-type
and :last-child/:last-of-type
when you're interested in styling the first and last element (only, or differently from other nth elements over competing :nth-of-type()
rules) and you want these rules to apply to the first and last even when the number of elements can vary.
Even if you do know the number of elements in advance, and even if this number will never change, :nth-of-type(X)
where X is the number of elements doesn't make it immediately clear that it's referring to "whichever element is the last" and not some arbitrary Xth element:
div:nth-of-type(even) { background-color: yellow; }
div:nth-of-type(1) { background-color: red; }
div:nth-of-type(12) { background-color: green; }
This, of course, is highly subjective — you may know your layout intimately enough that you know there will always be exactly X elements, so the example above will always target the first and last, and you may be the only developer to ever see your code and so it's not going to matter to you. That's why I said it's a matter of semantics. (You could get away with using :nth-last-of-type(1)
... but then you might as well save yourself the keystrokes and use :last-of-type
instead.)
The only situation in which :nth-of-type(X)
would be preferable is if you plan to extend this with additional :nth-of-type()
rules, each styling a specific element differently from the first two:
div:nth-of-type(1) { background-color: red; }
div:nth-of-type(2) { background-color: green; }
/* Added */
div:nth-of-type(3) { background-color: blue; }
In other words, when you want the rule that applies to the second element (the "last") to continue applying to the second element even when a third element is added — and you don't want that rule to then apply to the third (the new "last") element when that happens — use :nth-of-type(2)
, even if for example only 2 elements appear in the layout by default. At this point, you are no longer dealing with first/last semantics, but you are (and have all along been) dealing with nth semantics.
In such a situation, it might seem unnecessary to then use :nth-of-type(1)
over :first-of-type
, since the first element will always be the first no matter how many elements you add or remove from your layout. Which one you use in that case is indeed down to personal preference — for example, I would prefer :nth-of-type(1)
for consistency with the other rules so it doesn't look like the odd one out:
div:first-of-type { background-color: red; } /* Looks out of place... */
div:nth-of-type(2) { background-color: green; } /* ... when every other element... */
div:nth-of-type(3) { background-color: blue; } /* ... is numbered */
Additionally, what about an unusual scenario where a coder only has control over the stylesheet and the HTML is extremely unlikely to but technically liable to changing?
That's not all that unusual actually. If the HTML is extremely unlikely to change, then it's likely that the layout doesn't support it and is therefore not going to continue to work correctly if it does change. Whether you use first/last or nth isn't going to make much of a difference, so my advice of choosing based on semantics remains.
For the sake of completeness, there is one additional catch when it comes to :first-child
: unlike :last-child
, :only-child
, :nth-child()
, and all of the type-based variants (:*-of-type
), :first-child
was introduced in CSS2 and therefore several very old browsers only support that without supporting any of the rest.
In this day and age you probably don't have to worry about this, but if you did want your layout to gracefully degrade on very old browsers, you might consider using :nth-child(1)
so that it fails on unsupported browsers along with all the other :nth-child()
rules, rather than having the first element styled and the rest not, which depending on your layout might look ugly at best or cause adverse layout problems at worst.