In the world of HTML, our web applications produce an HTML outline in the browser. The HTML outline is sectioned off by different categories of content, among those, the
heading content exists. With these, we can layout down the blueprint for our work. Lately, I've been practicing somewhat of HTML first prototyping to improve my accessibility skills.
For me, the idea behind HTML first prototyping is to create a site or web application that will have a better, more scalable and standard abiding structure. In my experience when I apply the CSS styles as I develop the HTML, I end up adding more accessibility violations. This is due to the fact that styling semantic HTML is not an easy feat, so to make it look good (or out of frustration 😅) I introduce, knowingly or unknowingly, a11y (accessibility) violations.
In this post, I want to focus on the
h1-h6 heading tags. These
h# tags are known and described by the HTML docs as
Heading content and they define the headings of a section. In this definition, a section is a container for some DOM nodes in the original tree. Source
When the browser looks at our HMTL document or the page we are on, it will walk across it (top to bottom), and it will divide it into sections or segments -- creating the outline. Screen readers and assistive technologies use this outline to navigate and deliver the outcome to their users. Hence, why it is important for us to write it in the "right way". When a screenreader encounters this
h# element within a section, it will rank them according to their number, 1 being the most important in the hierarchy, and 6 the least important.
h1 tag will create a content section (not the same as the section above),
h2 will create a content subsection, and so on. It is important to note that equal rank heading tags, do not create nested sections. Meaning
h1 will always be the highest and everything in between is represented by that
h1. Assistive technology will interpret and announce an
h1 as the main heading for that page. If we have more than one it will cause conflict. When subsequent headings of equal or higher rank are added they create implied sections, this is one of the reasons why it is important to only have one upper-level heading per page.
Meaning that this:
<div> <h1>Welcome to this page</h1> <h2>Second level</h2> <h3>Third level</h3> <h4>Fourth level</h4> <h5>Fifth level</h5> <h6>Sith level</h6> </div>
Will be interpreted the same way like this (in terms of their section outline):
<div> <h1>Welcome to this page</h1> <section> <h2>Second level</h2> </section> <section> <h3>Third level</h3> </section> <article> <h4>Fourth level</h4> <h5>Fifth level</h5> </article> <h6>Sith level</h6> </div>
There was some debate some years ago to create the
Natural Document Outline, in which headings would be able to create nested accessible sections, thus allowing a user to add multiple
h1 tags inside the same document. However, this HTML 5 heading algorithm never saw the light of day. No assistive technology to this day supports it.
The first element of the heading content will represent the heading for that section. It can be written at any spot in your HTML code but to assistive technology, it will be interpreted and announced in the order that the current HTML outline algorithm places it in.
<section> <h2>Welcome to my page!</h2> <h1>Hello dev.to!</h1> <p>This can be a description</p> </section>
<section> <h1>Hello dev.to!</h1> <h2>Welcome to my page!</h2> <p>This can be a description</p> </section>
are both semantically correct. In both examples,
h1 will be interpreted as the heading of the page no matter the order that it was written in. If no CSS is applied, the first example would look out of order since
h1 has a larger size.
This brings me to another good point, to some it might be obvious, but the docs advise against skipping levels and using heading elements to style subtitles, alternative titles, content text, and/or markup-subheadings. In other words, we should attempt to maintain the hierarchical order in our document,
h1 -> h3 -> h5, etc. After what I have learned it seems logical because behind the scenes they create these sections and sub-sections. So, visually it might look good and even render a good user experience, however, it would most likely be considered inaccessible for assistive technologies.
On a closing note, you can give the heading property to other HTML elements through aria-* and role attributes.
<div role="heading" aria-level="1">Header</div>
role attribute tells assistive technologies that this element should be treated as a heading. The
aria-level="1" tells what rank the heading will have. To an assistive technology, this would be the equivalent of:
Using tools like Lighthouse audit or axe, which both exist as chrome dev tool extensions, really helps me out identify any a11y violations. I've gotten into the habit of running audits on both these tools early on and as I am developing (accessibility driven development!) to make sure my HTML is on point.
Thanks for reading! I hope to read some of your feedback on what I have learned, if anything is missing or if anything can be added to my knowledge!