Search code examples
svgaccessibilitygatsby

Svg inside h1 tag


I have a Gatsby project, where where I would like to use an svg as my main heading.

import Header from "../images/header.svg"

return (
  <h1>
      <Header/>
  </h1>
)

Thers is no text in the svg (the text is made purely using rects and paths), so what do I do in terms of accessibility and SEO optimization?


Solution

  • Two ways to address this, visually hidden text or by adding a <title> to your SVG.

    Do not use aria-label as support is not great (you will see people recommending that for SVGs, aria-label does not tend to work well on static / non-interactive elements).

    Visually Hidden text (screen reader only text)

    Visually hidden text is not visible on the screen but will still be read by a screen reader.

    Please use the CSS class below to visually hide text, it has better compatibility and is future proofed compared to most current "screen reader only" classes as explained in this answer I gave

    .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 */
    }
    <h1>
      <span class="visually-hidden">Welcome To Our Site</span>
        <svg aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
            <path fill="#666" d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z">
            </path>
        </svg>
    </h1>

    important: notice how I add focusable="false" as well as aria-hidden="true" to the SVG, this is to fix a bug with Internet Explorer where SVGs are focusable and to hide the SVG from screen readers. I used a youtube icon to represent your text as that was the closest SVG I had to hand!

    Add a <title> element to your SVG.

    The <title> element is effectively the same as alt on a normal image. Using this gives the screen reader something to announce.

    Obviously you would then remove the aria-hidden="true" from it so it can be read by a screen reader!

    Update after comments to include best practices for <title> and or <desc>

    Thanks to the comments I realised this answer was lacking some key information on how to correctly use a <title>.

    In this answer I gave I referenced a series of tests by deque which show that the most reliable method for labelling an SVG for screen readers using WAI-ARIA was to use aria-labelledby and point that to the <title> (and <desc> if you have both).

    So a rough idea of how to do this is as follows:

    <h1>
        <svg aria-labelledby="welcome-title" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
            <title id="welcome-title">Welcome To Our Site</title>
            <path fill="#666" d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z">
             </path>
        </svg>
    </h1>

    Which is better?

    Go for visually hidden text.

    It works all the way back to IE6 which predates SVG!

    It also works in a text only browser (one that does not understand CSS) as it will still be displayed. It is an edge case but still a win for visually hidden text!