What is the difference between p:nth-child(2)
and p:nth-of-type(2)
?
As per W3Schools CSS Selector Reference:
p:nth-child(2)
: Selects every <p>
element that is the second child of its parent.p:nth-of-type(2)
: Selects every <p>
element that is the second <p>
element of its parent.The difference seem to be child of its parent and <p>
element of its parent.
If we are already mentioning the element type as <p>
in both the cases and the keyword parent establishes a parent-child relation, so what can be the difference?
As a general rule, if you want to select an interval of a selector regardless of the type of element it is, use nth-child . However, if you want to select a specific type only and apply an interval selection from there, use nth-of-type .
The :first-child: The :first-child selector is used to select those elements which are the first-child elements. For :first-child selector the <! DOCTYPE> must be declared for IE8 and earlier versions. The :first-of-type: The :first-of-type Selector is used to targeting the first child of every element of it's parent.
The :nth-of-type() pseudo-class represents an element that has an+b siblings with the same expanded element name before it in the document tree, for any zero or positive integer value of n, and has a parent element.
There cannot be a way to select :nth-of-type() of a class, because :nth-of-type() only selects the nth child of its type.
For p:nth-child(2)
it selects the second element of its parent element if it's a paragraph whereas p:nth-of-type(2)
will select the second paragraph of its parent element. If you are still confused let's make me clarify it for you. Consider the code snippet below:
<section>
<h1>Words</h1>
<p>Little</p>
<p>Piggy</p> <!-- Want this one -->
</section>
Here, p:nth-child(2)
will select <p>Little</p>
because it is the second child of its parent and it a paragraph element.
But, Here, p:nth-of-type(2)
will select <p>Piggy</p>
because it will select the second paragraph among all the paragraph of its parent.
Help from: https://css-tricks.com/the-difference-between-nth-child-and-nth-of-type/
This question may remind you of What is the difference between :first-child and :first-of-type? — and in fact, a lot of parallels can be drawn between the two. Where this question greatly differs from the other is the arbitrary integer argument X, as in :nth-child(X)
and :nth-of-type(X)
. They're similar in principle to their "first" and "last" counterparts, but the potentially matching elements vary greatly based on what's actually in the page.
But first, some theory. Remember that simple selectors are independent conditions. They remain independent even when combined into compound selectors. That means that the p
neither is influenced by, nor influences, how :nth-child()
or :nth-of-type()
matches. Combining them this way simply means that elements must match all of their conditions simultaneously in order to match.
Here's where things get interesting. This independent matching means I can get pretty creative in how I express compound (and complex) selectors in terms of plain English, without changing the meaning of the selectors. In fact, I can do so right now in a way that makes the difference between :nth-child(2)
and :nth-of-type(2)
seem so significant that the pseudo-classes might as well be completely unrelated to each other (except for the "siblings" part anyway):
p:nth-child(2)
: Select the second child among its siblings if and only if it is a p
element.
p:nth-of-type(2)
: Select the second p
element among its siblings.
All of a sudden, they sound really different! And this is where a bit of explanation helps.
Any element may only have a single child element matching :nth-child(X)
for any integer X at a time. This is why I've chosen to emphasize "the second child" by mentioning it first. In addition, this child element will only match p:nth-child(X)
if it happens to be of type p
(remember that "type" refers to the tagname). This is very much in line with :first-child
and :last-child
(and, similarly, p:first-child
and p:last-child
).
There's two aspects to :nth-of-type(X)
on the other hand:
Because the "type" in :nth-of-type()
is the same concept as the "type" in a type selector, this family of pseudo-classes is designed to be used in conjunction with type selectors (even though they still operate independently). This is why p:nth-of-type(2)
can be expressed as succinctly as "Select the second p
element among its siblings." It just works!
However, unlike :first-of-type
and :last-of-type
, the X requires that there actually be that many child elements of the same type within their parent element. For example, if there's only one p
element within its parent, p:nth-of-type(2)
will match nothing within that parent, even though that p
element is guaranteed to match p:first-of-type
and p:last-of-type
(as well as, by extension, p:only-of-type
).
An illustration:
<div class="parent">
<p>Paragraph</p>
<p>Paragraph</p> <!-- [1] p:nth-child(2), p:nth-of-type(2) -->
<p>Paragraph</p>
<footer>Footer</footer>
</div>
<div class="parent">
<header>Header</header>
<p>Paragraph</p> <!-- [2] p:nth-child(2) -->
<p>Paragraph</p> <!-- [3] p:nth-of-type(2) -->
<footer>Footer</footer>
</div>
<div class="parent">
<header>Header</header>
<figure>Figure 1</figure>
<p>Paragraph</p> <!-- [4] -->
<footer>Footer</footer>
</div>
<div class="parent">
<header>Header</header>
<p>Paragraph</p> <!-- [2] p:nth-child(2) -->
<figure>Figure 1</figure>
<hr>
<figure>Figure 2</figure> <!-- [5] .parent > :nth-of-type(2) -->
<p>Paragraph</p> <!-- [5] .parent > :nth-of-type(2) -->
<p>Paragraph</p>
<footer>Footer</footer>
</div>
What's selected, what's not, and why?
Selected by both p:nth-child(2)
and p:nth-of-type(2)
The first two children of this element are both p
elements, allowing this element to match both pseudo-classes simultaneously for the same integer argument X, because all of these independent conditions are true:
p
element; andp
element within its parent.Selected by p:nth-child(2)
only
This second child is a p
element, so it does match p:nth-child(2)
.
But it's the first p
element (the first child is a header
), so it does not match p:nth-of-type(2)
.
Selected by p:nth-of-type(2)
only
This p
element is the second p
element after the one above, but it's the third child, allowing it to match p:nth-of-type(2)
but not p:nth-child(2)
. Remember, again, that a parent element can only have one child element matching :nth-child(X)
for a specific X at a time — the previous p
is already taking up the :nth-child(2)
slot in the context of this particular parent element.
Not selected
This p
element is the only one in its parent, and it's not its second child. Therefore it matches neither :nth-child(2)
nor :nth-of-type(2)
(not even when not qualified by a type selector; see below).
Selected by .parent > :nth-of-type(2)
This element is the second of its type within its parent. Like :first-of-type
and :last-of-type
, leaving out the type selector allows the pseudo-class to potentially match more than one element within the same parent. Unlike them, how many it actually matches depends on how many of each element type there actually are.
Here, there are two figure
elements and three p
elements, allowing :nth-of-type(2)
to match a figure
and a p
. But there's only one header
, one hr
, and one footer
, so it won't match elements of any of those types.
In conclusion, :nth-child()
and :nth-of-type()
, with an integer argument X (i.e. not in the form An+B with a coefficient A of n), function pretty similarly to :first-child
/:last-child
and :first-of-type
/:last-of-type
, with the major difference being that the argument, along with the page itself, influences how many different elements may be matched with :nth-of-type()
.
Of course, there's a whole lot more to :nth-child()
and :nth-of-type()
than just a simple integer argument, but needless to say the details and possibilities thereof are outside the scope of this question.
p:nth-child(2){background:#f00;}
p:nth-of-type(2){background:#0f0;}
<div>
<div>first child</div>
<p>second child and first element of class "p"</p>
<p>third child and second element of class "p"</p>
<p>fourth child and third element of class "p"</p>
</div>
The other answers hightlighted the main difference between both selectors which is the fact that nth-child
will consider all the elements inside the same container (siblings elements) and nth-of-type
will consider all the elements with the same type inside the same container.
The
:nth-child(an+b)
pseudo-class notation represents an element that has an+b-1 siblings before it in the document treerefThe
:nth-of-type(an+b)
pseudo-class notation represents an element that has an+b-1 siblings with the same expanded element name before it in the document treeref
From this we can add another important difference between both selectors which is the fact that nth-of-type
is generally used with a tag selector whereas nth-child
doesn't need a tag selector. In other words, nth-of-type
can select more than one element but nth-child
can select only one element. Adding a tag selector with nth-of-type
will restrict the selection to one element and adding a tag selector to nth-child
will simply add more restriction to the one element we are targeting.1
This selector will select the 2nd child of .container
.
.container :nth-child(2) {
border:1px solid red;
}
<div class="container">
<p>aaa</p>
<p>aaa</p>
<h1>title</h1>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<h1>title</h1>
</div>
This is the same selector as above but we add a tag restriction: Find the 2nd child of .container
, if it's a p
tag then select it.
.container p:nth-child(2) {
border:1px solid red;
}
<div class="container">
<p>aaa</p>
<p>aaa</p>
<h1>title</h1>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<h1>title</h1>
</div>
If we change p
with h1
nothing will be selected because the 2nd child isn't a h1
:
.container h1:nth-child(2) {
border:1px solid red;
}
<div class="container">
<p>aaa</p>
<p>aaa</p>
<h1>title</h1>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<h1>title</h1>
</div>
This selector will select the 2nd p
and the 2nd h1
. nth-of-type
will behave like nth-child
after grouping elements by the same type.
.container :nth-of-type(2) {
border:1px solid red;
}
<div class="container">
<p>aaa</p>
<p>aaa</p>
<h1>title</h1>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<h1>title</h1>
</div>
So we select the 2nd child inside this:
<div class="container">
<p>aaa</p>
<p>aaa</p> <-- this one -->
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
</div>
Then the 2nd child inside this:
<div class="container">
<h1>title</h1>
<h1>title</h1> <-- this one -->
</div>
Adding a tag selector will simply restrict the selection to only one group of element:
.container p:nth-of-type(2) {
border:1px solid red;
}
.container h1:nth-of-type(2) {
border:1px solid green;
}
<div class="container">
<p>aaa</p>
<p>aaa</p>
<h1>title</h1>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<h1>title</h1>
</div>
If your container contains only one type of element both selectors will for sure give the same result but will not behave the same (i.e. the alogirthm behind will be different). You may also notice that if you remove the tag selector from both you will also have the same result:
.container :nth-of-type(2) {
border:1px solid red;
}
.container :nth-child(2) {
color:red;
}
/* The below will also select the same
.container p:nth-child(2)
.container p:nth-of-type(2)
.container *:nth-child(2)
.container *:nth-of-type(2)
*/
<div class="container">
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
<p>aaa</p>
</div>
Another difference (this is a personal thought) may be the performance of both. nth-child
can be faster since it consider all the siblings elements at once so it's like we will have one loop to check all the elements. nth-of-type
need to consider different type of elements not at the same time so we will probably have more processing thus it's slower (This is my own conclusion based on how both works. I have no formal proof of it).
1: I am considering a selection inside one container using an integer within nth-child/nth-of-type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With