One mistake I’ve seen made a few times is the notion that CSS’s nth-child
pseudoselector acts like jQuery’s :eq
pseudoselector.
jQuery’s :eq(n)
pseudoselector gives you a single element that is at index n
out of all matched elements. While this is certainly a useful selector to have, it’s unfortunately not supported in standard CSS. If you find yourself repeatedly using :eq
in your jQuery code, be careful that you are not relying too heavily on :eq
to the point where your styles are difficult to match in “pure” CSS.
If we were to express :nth-child
in terms of the :eq
selector, it would be like using :eq
scoped to all of the immediate descendant contents of a single element. Or in my own words, :nth-child
adds a constraint to the selector that the matched element must be the nth element in its parent container.
So if we had a snippet of HTML like
<div>
<div id="bar1" class="foo"></div>
<div id="bar2" class="foo"></div>
<div id="bar3" class="foo"></div>
</div>
Then the selector .foo:nth-child(2)
will match the div #bar2
. If we insert another element at the front of the container:
<div>
<p>Shift!</p>
<div id="bar1" class="foo"></div>
<div id="bar2" class="foo"></div>
<div id="bar3" class="foo"></div>
</div>
And again we select .foo:nth-child(2)
, we match the div #bar1
because the 2nd child of the container also matches .foo
.
Thus, in this second example, if we try .foo:nth-child(1)
or the equivalent .foo:first-child
, we will not match any elements because the first child element in that container — the p
tag — does not match .foo
.
Likewise, :nth-child
can match children in multiple containers. In the HTML snippet:
<div>
<p>Shift!</p>
<div id="bar1" class="foo"></div>
<div id="bar2" class="foo"></div>
<div id="bar3" class="foo"></div>
</div>
<div>
<div id="quux" class="foo"></div>
</div>
the selector .foo:last-child
will match the divs #bar3
and #quux
; but .foo:first-child
or .foo:nth-child(1)
will only match #quux
because the first child of the first container is, again, not a .foo
.
About the Author