Find an interactive version of this article on my website
Currently, if we want to select all the headings in an HTML document, we can do it by concatenating all the selectors in a single rule:
h1, h2, h3, h4, h5, h6 {
/* code here */
}
This is clunky and limited. And if we want to select only certain heading levels, we have to write something even messier and clunkier.
There are two new features in CSS that can help with this task:
-
:heading
pseudo-class. -
:heading()
pseudo-class function.
NOTE: These features are still experimental and not widely supported. At the time of writing this article (September 2025), only Firefox Nightly has implemented them, so you'll need that browser to test them.
Let's check each of them separately.
:heading
:heading
is a pseudo-class that will select all headings within the scope (by default, the whole document). That means any h1
, h2
, h3
, h4
, h5
, or h6
tag.
Notice how there are two restrictions:
- It will select ALL the headings, independently of their level. It doesn't distinguish between
h1
andh2
,h3
orh6
, etc. It's all or nothing. - It will only select
h?
tags, ignoring elements identified as headings using theheading
ARIA role.
Here's a quick example:
:heading {
color: red;
}
<h1>Page Title</h1>
<h2>Chapter Title</h2>
<p>Some text</p>
<h3>Section title</h3>
As mentioned above, :heading
is a pseudo-class, and it will have the same specificity weight as a class (0-1-0
).
:heading()
:heading()
is a pseudo-class function that provides more flexibility than :heading
as it takes a list of one or more levels to select. For example, :heading(2, 3)
will select all the h2
and h3
, but not an h1
.
You might ask, "But, Álvaro, why not just use the selector h2, h3
? It would be easier and shorter!"
Great question. While a heading level is usually indicated by the number in the tag (h1
is level 1, h2
is level 2, etc.), there are ways reset and update a heading level. For example, using the HTML attributes headingoffset
or headingreset
(not fully supported either, but that's other story).
Unfortunately, just as elements with role="heading"
are not recognized as headings by :heading
, using aria-level
is also not enough for CSS to recognize a new heading level.
:heading(2, 3) {
color: red;
}
<h1>Page Title</h1>
<h2>Chapter Title</h2>
<p>Some text</p>
<h3>Section title</h3>
A trick when using :heading()
: the arguments don't have to be strictly numeric. We can use An + B
functional notation (e.g., 2n + 1
), or keywords like odd
and even
to select the heading we want.
Bibliography and Links
The new CSS heading pseudo-classes and functions are easy, simple and powerful. They are a convenient and clean way to style headings.
If you want to learn more, visit these sites:
Top comments (0)