CSS :heading() Pseudo-Class

The CSS :heading() pseudo-class selects heading elements based on their heading levels. It accepts one or more heading level numbers, allowing developers to style specific headings without writing separate selectors for each HTML heading element.

:heading() Syntax

:heading(level) {
  property: value;
}

The :heading() pseudo-class accepts one or more comma-separated positive integers representing heading levels.

Single Heading Level

:heading(2) {
  color: #0088cc;
}

This rule selects second-level headings, including HTML <h2> elements.

Multiple Heading Levels

:heading(2, 3) {
  color: #003366;
}

This rule selects second- and third-level headings.

Combining with Other Selectors

article :heading(2, 3) {
  margin-bottom: 12px;
}

This selector targets second- and third-level headings inside an <article> element.

How :heading() Works

The :heading() pseudo-class matches elements that the document language identifies as headings at the specified levels.

In HTML, the standard heading elements are <h1> through <h6>. Each element has a corresponding heading level.

Matching Heading Levels

<h1>Main Heading</h1>
<h2>Section Heading</h2>
<h3>Subsection Heading</h3>
:heading(2) {
  color: #0088cc;
}

Only the <h2> matches this selector in a browser that supports :heading().

Based on Heading Level

The selector uses an element's heading level rather than its appearance. Changing the font size of a heading does not change which :heading() selector matches it.

Not Based on Document Position

The number inside :heading() represents a heading level, not the position of a heading among its siblings.

For example, :heading(2) does not mean the second heading on a webpage.

Selecting Heading Levels

HTML defines six standard heading levels, numbered from 1 through 6.

HTML Heading Levels

Selector HTML Element Heading Level
:heading(1) <h1> 1
:heading(2) <h2> 2
:heading(3) <h3> 3
:heading(4) <h4> 4
:heading(5) <h5> 5
:heading(6) <h6> 6

Selecting First-Level Headings

:heading(1) {
  font-size: 2rem;
  color: #003366;
}

This rule styles first-level headings.

Selecting Lower-Level Headings

:heading(4, 5, 6) {
  font-weight: bold;
  color: #666;
}

This rule applies shared styles to fourth-, fifth-, and sixth-level headings.

Multiple Heading Levels

Multiple heading levels can be included in a single :heading() selector by separating the level numbers with commas.

Selecting Two Levels

:heading(2, 3) {
  border-bottom: 1px solid #ccc;
  padding-bottom: 8px;
}

Second- and third-level headings receive the same border and padding.

Selecting Several Levels

:heading(2, 3, 4) {
  margin-top: 20px;
  margin-bottom: 10px;
}

This rule applies consistent spacing to heading levels 2, 3, and 4.

Selecting Nonconsecutive Levels

:heading(1, 3, 5) {
  color: #006699;
}

The heading levels do not need to be consecutive.

No Heading Range Syntax

The function does not use a numeric range to select several heading levels. Each desired level must be listed explicitly.

:heading() vs. :heading

The functional and nonfunctional forms are related but match different sets of headings.

Comparison

Selector Matching Behavior
:heading Matches headings at any level.
:heading(1) Matches first-level headings.
:heading(2, 3) Matches second- and third-level headings.
:heading(4, 5, 6) Matches fourth-, fifth-, and sixth-level headings.

Styling All Headings

:heading {
  font-family: Arial, sans-serif;
}

Styling Selected Heading Levels

:heading(2, 3) {
  color: #0088cc;
}

Use :heading for shared styles across all heading levels and :heading() when only particular levels should match.

:heading() vs. :is()

The :is() pseudo-class can group ordinary HTML heading selectors and provides a broadly supported alternative.

Using :heading()

:heading(2, 3) {
  color: #0088cc;
}

Using :is()

:is(h2, h3) {
  color: #0088cc;
}

For standard HTML headings, these selectors match the same elements when :heading() is supported.

Key Differences

Feature :heading(2, 3) :is(h2, h3)
Matches HTML h2 and h3 Yes Yes
Uses heading level numbers Yes No
Specificity 0-1-0 0-0-1
Browser availability Limited Widely available

Use :is() when consistent styling across older and current browsers is required.

:heading() Specificity

The :heading() pseudo-class contributes a specificity of 0-1-0, regardless of how many heading levels are included in its argument list.

Specificity Examples

Selector Specificity
:heading(2) 0-1-0
:heading(2, 3) 0-1-0
article :heading(2) 0-1-1
:heading(2).featured 0-2-0
h2 0-0-1
:is(h2, h3) 0-0-1

Specificity Example

h2 {
  color: #333;
}
:heading(2) {
  color: #0088cc;
}

When both selectors match and other cascade factors are equal, the :heading(2) declaration takes precedence because the pseudo-class has greater specificity.

Reducing Specificity

:where(:heading(2, 3)) {
  margin-bottom: 12px;
}

The :where() pseudo-class reduces the specificity contribution of the entire selector to zero.

Practical Uses

The :heading() pseudo-class can group heading levels that share common visual styles.

Section Heading Colors

:heading(2, 3) {
  color: #003366;
}

Second- and third-level headings share a text color.

Smaller Heading Styles

:heading(4, 5, 6) {
  font-size: 0.875rem;
  font-weight: bold;
}

Lower-level headings receive a consistent font size and weight.

Article Heading Spacing

article :heading(2, 3, 4) {
  margin-top: 20px;
  margin-bottom: 10px;
}

Selected headings inside an article receive consistent spacing.

Headings with Classes

:heading(2, 3).featured {
  border-left: 4px solid #0088cc;
  padding-left: 10px;
}

This rule styles second- and third-level headings that also have the featured class.

Limitations

The :heading() pseudo-class is intended for semantic heading levels, but its browser availability remains limited.

Limited Browser Support

Browsers that do not recognize :heading() ignore CSS rules using the selector.

Requires Heading Levels

The function requires heading level numbers. Unlike :heading, the functional form does not select all heading levels when its parentheses are empty.

Not a Position Selector

The selector does not select the first, second, or third heading according to document order. It matches semantic heading levels.

Does Not Change HTML Semantics

Using :heading(2) does not convert another element into an <h2> or change its accessibility semantics.

Compatibility Fallback

:is(h2, h3) {
  color: #003366;
}

This alternative matches the corresponding standard HTML heading elements in browsers that support :is().

Accessibility

HTML headings organize webpage content into a meaningful structure that helps users navigate and understand the document.

Use Appropriate Heading Levels

Choose heading levels according to the document hierarchy rather than their default visual appearance.

Maintain Heading Order

Use a logical heading sequence. Avoid skipping levels solely to achieve a preferred font size.

Readable Heading Styles

Maintain sufficient contrast, readable font sizes, and clear spacing between headings and surrounding content.

CSS and Semantics

CSS changes visual presentation but does not change the semantic heading level exposed to assistive technologies.

Best Practices

  • Use :heading() when several specific heading levels need shared styling.
  • List each desired heading level explicitly.
  • Use :heading when styles should apply to headings at every level.
  • Provide a compatible fallback using standard heading selectors or :is().
  • Remember that heading numbers represent levels, not document positions.
  • Consider specificity when combining heading selectors with classes.
  • Preserve semantic HTML and a logical heading hierarchy.
  • Test heading styles across browsers.

:heading() Example

This example styles second- and third-level headings using :heading(2, 3). A compatible fallback ensures that the headings remain styled in browsers without support for the functional pseudo-class.

HTML

<div class="heading-demo">
  <h1>Heading Level 1</h1>
  <h2>Heading Level 2</h2>
  <h3>Heading Level 3</h3>
  <h4>Heading Level 4</h4>
  <p>This paragraph is not a heading.</p>
</div>

CSS

.heading-demo :is(h2, h3) {
  color: #003366;
  border-bottom: 1px solid #ccc;
  padding-bottom: 6px;
}
.heading-demo :heading(2, 3) {
  color: #0088cc;
  border-bottom-color: #0088cc;
}
.heading-demo h1 { font-size: 1.375rem; }
.heading-demo h2 { font-size: 1.25rem; }
.heading-demo h3 { font-size: 1.125rem; }
.heading-demo h4 { font-size: 1rem; }

In browsers supporting :heading(), the second- and third-level headings appear in a brighter blue. Other browsers use the darker blue fallback. The first- and fourth-level headings are not selected by either rule.

Browser Result

Play in Editor

Note: The fallback uses :is(h2, h3). The brighter blue styling indicates whether the browser applies the :heading(2, 3) rule.

Browser Support

Baseline: Limited availability. The :heading() pseudo-class is not consistently supported across major browsers. Standard heading selectors and :is() provide more broadly compatible alternatives.

For current compatibility information, visit Can I Use? and search for :heading().

Specifications

The :heading() pseudo-class is defined in CSS Selectors Level 4 as part of the heading pseudo-classes. It allows heading levels to be specified using a comma-separated list of positive integers.

Selectors Level 4 - Heading Pseudo-Classes