For accessibility purposes, you could think of headings as a table of contents. But what if there are headings without contents?
On a web page, a heading (
h3 etc) signposts ‘a section about X starts here’. Heading names are section names, in that sense. If, in a banana bread recipe, one heading says ‘Ingredients’, and the other says ‘Method’, expectations are set about what can be found where. Under the first heading, we’ll expect what goes into the banana bread, under the second we’ll expect some steps to follow.
Now, a problem I saw on a website recently: headings with no content. The issue wasn’t empty
hx elements, it was that there was no content between these elements and the next. This can happen when the heading element was picked merely for its looks, rather than as a way to indicate that there is some content—and what kind of content.
<h1>Banana bread</h1> <h2>It's tasty</h2> <!-- nothing --> <h2>It's healthy</h2> <!-- nothing --> <h2>It can be anyway</h2>
On a site with beautiful heading styles, this could look great, but structurally it is unhelpful, because when someone navigates to one of these
h2’s, they find nothing.
It could also constitute a failure of WCAG 1.3.1: Info and relationships, because you’re basically claiming a structural relationship when there isn’t one.
So, the two questions to ask for headings:
- useful description: does this clearly say what kind of content I can find underneath?
- content: is there any content available underneath?
In the example above, only the
h1 meets the criterion of being something we would want to navigate to. The bits underneath are more of a list of unique selling points. Something like this would be better in this context:
<h1>Banana bread</h1> <ul> <li>It's tasty</li> <li>It's healthy</li> </ul>
Note: the problem is not multiple headings as such, it’s multiple headings of the same level, that have no non heading content that they are a description for.
When you use a heading element, you set the expectation of content—always have content between headings of the same level.
Thanks to Jules Ernst, who explained this problem to me first.
Update 8 September 2020: added nuance to whether this fails 1.3.1