What is the difference between p:nth-child(2) and p:nth-of-type(2)?
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 ap
element.p:nth-of-type(2)
: Select the secondp
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 whyp:nth-of-type(2)
can be expressed as succinctly as "Select the secondp
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 onep
element within its parent,p:nth-of-type(2)
will match nothing within that parent, even though thatp
element is guaranteed to matchp:first-of-type
andp: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)
andp:nth-of-type(2)
The first two children of this element are bothp
elements, allowing this element to match both pseudo-classes simultaneously for the same integer argument X, because all of these independent conditions are true:- it is the second child of its parent;
- it is a
p
element; and - it is the second
p
element within its parent.
Selected by
p:nth-child(2)
only
This second child is ap
element, so it does matchp:nth-child(2)
.But it's the first
p
element (the first child is aheader
), so it does not matchp:nth-of-type(2)
.Selected by
p:nth-of-type(2)
only
Thisp
element is the secondp
element after the one above, but it's the third child, allowing it to matchp:nth-of-type(2)
but notp: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 previousp
is already taking up the:nth-child(2)
slot in the context of this particular parent element.Not selected
Thisp
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 threep
elements, allowing:nth-of-type(2)
to match afigure
and ap
. But there's only oneheader
, onehr
, and onefooter
, 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.
nth-of-type vs nth-child
The nth-child
pseudo-class refers to the "Nth matched child element", meaning if you have a structure as follows:
<div>
<h1>Hello</h1>
<p>Paragraph</p>
<p>Target</p>
</div>
Then p:nth-child(2)
will select the second child which is also a p (namely, the p
with "Paragraph").p:nth-of-type
will select the second matched p
element, (namely, our Target p
).
Here's a great article on the subject by Chris Coyier @ CSS-Tricks.com
The reason yours breaks is because type refers to the type of element (namely, div
), but the first div doesn't match the rules you mentioned (.row .label
), therefore the rule doesn't apply.
The reason is, CSS is parsed right to left, which means the the browser first looks on the :nth-of-type(1)
, determines it searches for an element of type div
, which is also the first of its type, that matches the .row
element, and the first, .icon
element. Then it reads that the element should have the .label
class, which matches nothing of the above.
If you want to select the first label element, you'll either need to wrap all of the labels in their own container, or simply use nth-of-type(3)
(assuming there will always be 2 icons).
Another option, would (sadly) be to use... wait for it... jQuery:
$(function () {
$('.row .label:first')
.css({
backgroundColor:"blue"
});
});
How to use css selector nth-of-type and nth-child to locate element in Python Selenium
For completeness, I have added the </li>
, </ul>
and </class>
tags at the appropriate places and the ideal HTML will be:
<class id="class1">
<ul>
<li>
<strong>section 1</strong>
<a href="link.com/home1">some link 1</a>
</li>
<li>
<strong>section 2</strong>
<a href="link.com/home">some link 2</a>
</li>
</ul>
</class>
<class id="class1">
<ul>
<li>
<strong>section 3</strong>
<a href="link.com/home/abc">some link 3</a>
</li>
<li>
<strong>section 4</strong>
<a href="link.com/home/def">some link 4</a>
</li>
</ul>
</class>
To locate the href
attribute of section 2 you can use either of the following Locator Strategies:
Using
nth-child()
:class#class1 > ul li:nth-child(2) a[href$="home"]
Using
nth-child()
:class#class1 > ul li:nth-of-type(2) a[href$="home"]
Solution
To print the value of the href attribute you can use either of the following Locator Strategies:
Using
nth-child()
:print(driver.find_element(By.CSS_SELECTOR, "class#class1 > ul li:nth-child(2) a[href$='home']").get_attribute("href"))
Using
nth-child()
:print(driver.find_element(By.CSS_SELECTOR, "class#class1 > ul li:nth-of-type(2) a[href$='home']").get_attribute("href"))
tl; dr
What is the difference between p:nth-child(2) and p:nth-of-type(2)?
Why does the :nth-child(2) selector work on what I expect to be :first-child?
The :nth-child
selector ignores the elements type. div:nth-child(2)
selects a <div>
which is a second child.
If you want to select the first div, use the :nth-of-type(1)
or :first-of-type
selector.
Demo: http://jsfiddle.net/Z3Bcq/1/
What is the difference between nth-child() and eq()
The first one:
Nokogiri::CSS.xpath_for("div p:eq(2)")
# >> ["//div//p[position() = 2]"]
This is also known as //div//p[2]
and it means "return the second p
elements" no matter whether they have other sibling elements.
The second one:
Nokogiri::CSS.xpath_for("div p:nth-child(2)")
# >> ["//div//*[position() = 2 and self::p]"]
This means "find all elements in the second position, and return them ONLY if they also happen to be a p
.
Example
Consider the following HTML:
<html>
<body>
<div>
<p>Div1p1</p>
<i>Div1i1</i>
<p>Div1p2</p>
</div>
<div>
<p>Div2p1</p>
<p>Div2p2</p>
<p>Div2p3</p>
</div>
</body>
</html>
The output of //p[2]
will be:
<p>Div1p2</p>
<p>Div2p2</p>
because "Div1p2" is the second p
in the first div
, and "Div2p2" is the second p
in the second div
.
The output of //*[position()=2 and self::p]
will be:
<p>Div2p2</p>
because the second element of the first div is an i
, not a p
. But the second element of the second div also happens to be a p
so it matches.
Can I combine :nth-child() or :nth-of-type() with an arbitrary selector?
This is a very common problem that arises due to a misunderstanding of how :nth-child(An+B)
and :nth-of-type()
work.
In Selectors Level 3, the :nth-child()
pseudo-class counts elements among all of their siblings under the same parent. It does not count only the siblings that match the rest of the selector.
Similarly, the :nth-of-type()
pseudo-class counts siblings sharing the same element type, which refers to the tag name in HTML, and not the rest of the selector.
This also means that if all the children of the same parent are of the same element type, for example in the case of a table body whose only children are tr
elements or a list element whose only children are li
elements, then :nth-child()
and :nth-of-type()
will behave identically, i.e. for every value of An+B, :nth-child(An+B)
and :nth-of-type(An+B)
will match the same set of elements.
In fact, all simple selectors in a given compound selector, including pseudo-classes such as :nth-child()
and :not()
, work independently of one another, rather than looking at the subset of elements that are matched by the rest of the selector.
This also implies that there is no notion of order among simple selectors within each individual compound selector1, which means for example the following two selectors are equivalent:
table.myClass tr.row:nth-child(odd)
table.myClass tr:nth-child(odd).row
Translated to English, they both mean:
Select any
tr
element that matches all of the following independent conditions:
- it is an odd-numbered child of its parent;
- it has the class "row"; and
- it is a descendant of a
table
element that has the class "myClass".
(you'll notice my use of an unordered list here, just to drive the point home)
Selectors level 4 seeks to rectify this limitation by allowing :nth-child(An+B of S)
2 to accept an arbitrary selector argument S, again due to how selectors operate independently of one another in a compound selector as dictated by the existing selector syntax. So in your case, it would look like this:
table.myClass tr:nth-child(odd of .row)
Of course, being a brand new proposal in a brand new specification, this probably won't see implementation until a few years down the road.
In the meantime, you'll have to use a script to filter elements and apply styles or extra class names accordingly. For example, the following is a common workaround using jQuery (assuming there is only one row group populated with tr
elements within the table):
$('table.myClass').each(function() {
// Note that, confusingly, jQuery's filter pseudos are 0-indexed
// while CSS :nth-child() is 1-indexed
$('tr.row:even').addClass('odd');
});
With the corresponding CSS:
table.myClass tr.row.odd {
...
}
If you're using automated testing tools such as Selenium or scraping HTML with tools like BeautifulSoup, many of these tools allow XPath as an alternative:
//table[contains(concat(' ', @class, ' '), ' myClass ')]//tr[contains(concat(' ', @class, ' '), ' row ')][position() mod 2)=1]
Other solutions using different technologies are left as an exercise to the reader; this is just a brief, contrived example for illustration.
1 If you specify a type or universal selector, it must come first. This does not change how selectors fundamentally work, however; it's nothing more than a syntactic quirk.
2 This was originally proposed as :nth-match()
, however because it still counts an element relative only to its siblings, and not to every other element that matches the given selector, it has since as of 2014 been repurposed as an extension to the existing :nth-child()
instead.
What is the difference between :first-child and :first-of-type?
A parent element can have one or more child elements:
<div class="parent">
<div>Child</div>
<div>Child</div>
<div>Child</div>
<div>Child</div>
</div>
Among these children, only one of them can be the first. This is matched by :first-child
:
<div class="parent">
<div>Child</div> <!-- :first-child -->
<div>Child</div>
<div>Child</div>
<div>Child</div>
</div>
The difference between :first-child
and :first-of-type
is that :first-of-type
will match the first element of its element type, which in HTML is represented by its tag name, even if that element is not the first child of the parent. So far the child elements we're looking at have all been div
s, but bear with me, I'll get to that in a bit.
For now, the converse also holds true: any :first-child
is also :first-of-type
by necessity. Since the first child here is also the first div
, it will match both pseudo-classes, as well as the type selector div
:
<div class="parent">
<div>Child</div> <!-- div:first-child, div:first-of-type -->
<div>Child</div>
<div>Child</div>
<div>Child</div>
</div>
Now, if you change the type of the first child from div
to something else, like h1
, it will still be the first child, but it will no longer be the first div
obviously; instead, it becomes the first (and only) h1
. If there are any other div
elements following this first child within the same parent, the first of those div
elements will then match div:first-of-type
. In the given example, the second child becomes the first div
after the first child is changed to an 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>
Note that :first-child
is equivalent to :nth-child(1)
.
This also implies that while any element may only have a single child element matching :first-child
at a time, it can and will have as many children matching the :first-of-type
pseudo-class as the number of types of children it has. In our example, the selector .parent > :first-of-type
(with an implicit *
qualifying the :first-of-type
pseudo) will match two elements, not just one:
<div class="parent">
<h1>Child</h1> <!-- .parent > :first-of-type -->
<div>Child</div> <!-- .parent > :first-of-type -->
<div>Child</div>
<div>Child</div>
</div>
The same holds true for :last-child
and :last-of-type
: any :last-child
is by necessity also :last-of-type
, since absolutely no other element follows it within its parent. Yet, because the last div
is also the last child, the h1
cannot be the last child, despite being the last of its type.
:nth-child()
and :nth-of-type()
function very similarly in principle when used with an arbitrary integer argument (as in the :nth-child(1)
example mentioned above), but where they differ is in the potential number of elements matched by :nth-of-type()
. This is covered in detail in What is the difference between p:nth-child(2) and p:nth-of-type(2)?
p:nth-child(even) and p:nth-child(odd) losing count with intermediate div's placed after a few p 's
I think you probably want the functionality of nth-of-type
instead of nth-child
based on what you're describing. Article on the difference here https://css-tricks.com/the-difference-between-nth-child-and-nth-of-type/
Your example: https://jsfiddle.net/nh16ytq7/
Related Topics
Use CSS Variables with Rgba for Gradient Transparency
Ie11 Border Radius and Border Bug
Converting "Long Shadow" SASS Mixin to Less
Footer Consisting of Two Right Triangles
How to Reset or Override Ie CSS Filters
Change Font-Weight of Fontawesome Icons
Override Rmarkdown Theme in Order to Change HTML Page Width
CSS Sibling Selectors (Select All Siblings)
Select All Elements After Specific Element
CSS Expanding Based on Portrait or Landscape Screen Size
Ignoring Webkit-Specific CSS Selector in Firefox
Use Linear Gradient in CSS to Split Div in 2 Colors But Not in Equal Halves
How to Create a Triangular Shape with Curved Border
Scale HTML5 Video and Break Aspect Ratio to Fill Whole Site
How to Use the Matrix Transform and Other Transform CSS Properties