Matching the first/nth element of a certain type in the entire document
How can I specify :first-of-type
of the entire document?
I want to style the first <p>
of the HTML, no mater where it is located (I don't want to write section p:first-of-type
because it may be located elsewhere in a different HTML document).
p {
background:red;
}
p:first-of-type {
background:pink;
}
p:last-of-type {
background:yellow;
}
<body>
<section>
<p>111</p>
<p>222</p>
<p>333</p>
</section>
<p>444</p>
<p>555</p>
</body>
Solution 1:
With CSS alone this unfortunately isn't possible. The documentation for the :first-of-type
pseudo-class states:
The
:first-of-type
pseudo-class represents an element that is the first sibling of its type in the list of children of its parent element.
This means that :first-of-type
is applied to the first element of its type relative to its parent and not the document's root (or the body
element, in this case).
JavaScript solutions
:first-of-type
We can achieve this by introducing some JavaScript. All we need for this is JavaScript's querySelector()
method, which pulls the first matching element from the selector specified.
In this example I've altered your :first-of-type
pseudo-class to instead be a class of "first-of-type", then used JavaScript to add this class to the element returned when using querySelector('p')
:
document.querySelector('p').className += ' first-of-type';
p {
background:red;
}
p.first-of-type {
background: pink;
}
<body>
<section>
<p>111</p>
<p>222</p>
<p>333</p>
</section>
<p>444</p>
<p>555</p>
</body>
:nth-child
and :last-of-type
As for :nth-child
and :last-of-type
, we can instead make use of a similar method JavaScript gives us: querySelectorAll()
. This method pulls all matching elements into a NodeList (which is similar to an array), which we can then iterate through or select specific elements from within through the index:
var elems = document.querySelectorAll('p');
// nth-of-type = NodeList[n - 1]
// e.g. to select the 3rd p element ("333"):
if (elems.length >= 2)
elems[2].className += ' nth-of-type';
// last-of-type = NodeList length - 1
if (elems.length)
elems[elems.length - 1].className += ' last-of-type';
p {
background:red;
}
p.nth-of-type {
background: pink;
}
p.last-of-type {
background: yellow;
}
<body>
<section>
<p>111</p>
<p>222</p>
<p>333</p>
</section>
<p>444</p>
<p>555</p>
</body>
Note that I've included if
statements around both selectors to ensure the elems NodeList has enough elements, otherwise an error will be thrown.