Search code examples
htmlaccessibilitysemantic-markup

Semantically Appropriate Markup of Headings for Content Flow and Accessibility


I have a design that has a section that looks like the following:

enter image description here

As with anything, this could be marked up in several ways:

<section>
    <header>
        <p>About Area Title<p>
        <h2>Lorem ipsum[...]</h2>
    </header>

    <p>Lorem ipsum dolor sit amet[...]</p>
    <!-- ... -->
</section>

<!-- OR -->

<section>
    <p>About Area Title<p>
    <h2>Lorem ipsum[...]</h2>
    <p>Lorem ipsum dolor sit amet[...]</p>
    <!-- ... -->
</section>

<!-- OR -->

<section>
    <h2>About Area Title<h2>
    <h3>Lorem ipsum[...]</h3>
    <p>Lorem ipsum dolor sit amet[...]</p>
    <!-- ... -->
</section>

What would be the the best solution (might not be listed above) that not only is semantically correct but still preserves content flow and hierarchy for screen readers, bots, etc.?


Solution

  • I have an option for you not in the list.

    The reason I would recommend this is because of how screen reader users navigate a page, majority using headings and if you did it with a separate <p> to the heading that information may get missed (I am assuming that the "About Area Title" is significant here.)

    <section aria-labelledby="heading-a">
        <h2 id="heading-a">
            <span>About Area Title</span>
            <span class="visually-hidden">:</span>
            Lorem ipsum[...]
        <h2>
        <p>Lorem ipsum dolor sit amet[...]</p>
        <!-- ... -->
    </section>
    

    Now the above is assuming that the "About Area Title" bit makes sense as part of the heading for the section (which logically it should in most circumstances).

    What we then do is apply styling to both make the <span> smaller and to implement the visually hidden class to hide the : we use as a separator.

    The final thing is that it is a good practice to label a section so we just point it at the heading for that section using aria-labelledby and a corresponding ID on the heading.

    The following rough example shows you what I mean.

    h2{
        font-size: 2.5rem;
    }
    h2>span{
        font-size: 1rem;
        display: block;
    }
    .visually-hidden { 
        border: 0;
        padding: 0;
        margin: 0;
        position: absolute !important;
        height: 1px; 
        width: 1px;
        overflow: hidden;
        clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
        clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
        clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
        white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
    }
    <section aria-labelledby="heading-a">
        <h2 id="heading-a">
            <span>About Area Title</span>
            <span class="visually-hidden">:</span>
            Lorem ipsum[...]
        </h2>
        <p>Lorem ipsum dolor sit amet[...]</p>
        <!-- ... -->
    </section>