Um elemento pai pode ter um ou mais elementos filho:
<div class="parent">
<div>Child</div>
<div>Child</div>
<div>Child</div>
<div>Child</div>
</div>
Entre essas crianças, apenas uma delas pode ser a primeira. Isso é correspondido por :first-child:
<div class="parent">
<div>Child</div> <!-- :first-child -->
<div>Child</div>
<div>Child</div>
<div>Child</div>
</div>
A diferença entre :first-childe :first-of-typeé que :first-of-typecorresponderá ao primeiro elemento de seu tipo de elemento, que em HTML é representado por seu nome de tag, mesmo se esse elemento não for o primeiro filho do pai . Até agora, os elementos filhos que estamos vendo foram todos divs, mas tenha paciência comigo, vou chegar lá em breve.
Por enquanto, o inverso também é verdadeiro: qualquer :first-childum também é :first-of-typepor necessidade. Como o primeiro filho aqui também é o primeiro div, ele corresponderá a ambas as pseudo classes, bem como ao seletor de tipo div:
<div class="parent">
<div>Child</div> <!-- div:first-child, div:first-of-type -->
<div>Child</div>
<div>Child</div>
<div>Child</div>
</div>
Agora, se você mudar o tipo do primeiro filho divpara outra coisa, como h1, ainda será o primeiro filho, mas não será mais o primeiro divobviamente; em vez disso, ele se torna o primeiro (e único) h1. Se houver quaisquer outros divelementos seguindo este primeiro filho dentro do mesmo pai, o primeiro desses divelementos corresponderá div:first-of-type. No exemplo dado, o segundo filho se torna o primeiro divdepois que o primeiro filho é alterado para um h1:
<div class="parent">
<h1>Child</h1> <!-- h1:first-child, h1:first-of-type -->
<div>Child</div> <!-- div:nth-child(2), div:first-of-type -->
<div>Child</div>
<div>Child</div>
</div>
Observe que :first-childé equivalente a :nth-child(1).
Isso também implica que, embora qualquer elemento possa ter apenas um único elemento filho correspondente :first-childpor vez, ele pode e terá tantos filhos correspondendo à :first-of-typepseudo classe quanto o número de tipos de filhos que ela possui. Em nosso exemplo, o seletor .parent > :first-of-type(com uma *qualificação implícita de :first-of-typepseudo) corresponderá a dois elementos, não apenas a um:
<div class="parent">
<h1>Child</h1> <!-- .parent > :first-of-type -->
<div>Child</div> <!-- .parent > :first-of-type -->
<div>Child</div>
<div>Child</div>
</div>
O mesmo é verdadeiro para :last-childe :last-of-type: qualquer :last-childé por necessidade também :last-of-type, visto que absolutamente nenhum outro elemento o segue dentro de seu pai. Porém, como o último divé também o último filho, h1não pode ser o último filho, apesar de ser o último de seu tipo.
:nth-child()e :nth-of-type()funcionam de maneira muito semelhante em princípio quando usados com um argumento inteiro arbitrário (como no :nth-child(1)exemplo mencionado acima), mas onde eles diferem é no número potencial de elementos correspondidos por :nth-of-type(). Isso é abordado em detalhes em Qual é a diferença entre p: n-ésimo filho (2) e p: n-ésimo-do-tipo (2)?