Why does a link not take the of a contained <svg> as it's accessible name?</a></h1> </div> <div class="grid fw-wrap pb8 mb16 bb bc-black-075"> <div class="grid--cell ws-nowrap mr16 mb8" title="2016-01-12 19:07:53Z"> <span class="fc-light mr2">Asked</span> <time itemprop="dateCreated" datetime="2020-08-01T17:30:42.260" class="fromnow">Aug 01 '20 at 17:30</time> </div> <div class="grid--cell ws-nowrap mr16 mb8"> <span class="fc-light mr2">Active</span> <time class="fromnow" title="2020-08-03T07:09:59.797" datetime="2020-08-03T07:09:59.797">Aug 03 '20 at 07:09</a> </div> <div class="grid--cell ws-nowrap mb8" title="Viewed 882 times"> <span class="fc-light mr2">Viewed</span> 882 times </div> </div> <div id="mainbar" role="main" aria-label="questions and answers"> <div id="question" class="question" data-questionid="63208144" data-ownerid="3578997" data-score="0"> <div class="post-layout"> <div class="votecell post-layout--left"> <div class="js-voting-container grid jc-center fd-column ai-stretch gs4 fc-black-200" data-post-id="63208144"> <button class="js-vote-up-btn grid--cell s-btn s-btn__unset c-pointer"><svg aria-hidden="true" class="m0 svg-icon iconArrowUpLg" width="36" height="36" viewBox="0 0 36 36"><path d="M2 26h32L18 10 2 26z"></path></svg></button> <div class="js-vote-count grid--cell fc-black-500 fs-title grid fd-column ai-center" itemprop="upvoteCount" data-value="0">0</div> <button class="js-bookmark-btn s-btn s-btn__unset c-pointer py4"> <svg aria-hidden="true" class="svg-icon iconBookmark" width="18" height="18" viewBox="0 0 18 18"><path d="M6 1a2 2 0 00-2 2v14l5-4 5 4V3a2 2 0 00-2-2H6zm3.9 3.83h2.9l-2.35 1.7.9 2.77L9 7.59l-2.35 1.7.9-2.76-2.35-1.7h2.9L9 2.06l.9 2.77z"></path></svg> <div class="js-bookmark-count mt4" data-value=""></div> </button> </div> </div> <div class="postcell post-layout--right"> <div class="s-prose js-post-body" itemprop="text"><p>The way to provide an accessible name for an <code><img></code> element is via its <code>alt</code> attribute. Similarly, the way to provide an acessible name for an <code><svg></code> element is via its <code><title></code> element.</p> <p>If I have an <code>img</code> tag within an <code>a</code> tag, the accessible name of the link is the accessible name of the <code>img</code>. However, if I have an <code>svg</code> within an <code>a</code> tag, the link has has no accessible name even if the <code>svg</code> does. Why is this?</p> <p>This is apparent within both Lighthouse audits and also the Accessibility tab of Firefox dev tools.</p> <pre><code><a href="/fern"> <img src="/bracken" alt="Bracken" /> </a> </code></pre> <p><a class="external-link" href="https://i.stack.imgur.com/VUzEk.png" rel="nofollow noreferrer"><img alt="Using an img" src="../../images/3840609455.webp"/></a></p> <pre><code><a href="/fern"> <svg role="img" viewBox="0 0 100 100"> <title>Bracken</title> <use xlink:href="/ferns_sprite.svg#bracken"></use> </svg> </a> </code></pre> <p><a class="external-link" href="https://i.stack.imgur.com/ofKQS.png" rel="nofollow noreferrer"><img alt="enter image description here" src="../../images/3839560862.webp"/></a></p> <p>I could add an aria-label to the link, but that seems like duplication.</p></div> <div class="mt24 mb12"> <div class="post-taglist grid gs4 gsy fd-column"> <div class="grid ps-relative"> <a href="../../questions/tagged/svg" class="post-tag js-gps-track" title="show questions tagged 'svg'" rel="tag">svg</a> <a href="../../questions/tagged/accessibility" class="post-tag js-gps-track" title="show questions tagged 'accessibility'" rel="tag">accessibility</a> </div> </div> </div> <div class="mb0"> <div class="mt16 grid gs8 gsy fw-wrap jc-end ai-start pt4 mb16"> <div class="grid--cell mr16 fl1 w96"></div> <div class="post-signature owner grid--cell"> <div class="s-user-card s-user-card"> <time class="s-user-card--time" datetime="asked Aug 01 '20 at 17:30">asked Aug 01 '20 at 17:30</time> <a href="../../users/3578997/mark-fisher" class="s-avatar s-avatar__32 s-user-card--avatar"> <img class="s-avatar--image" src="../../users/profiles/3578997.webp" data-jdenticon-width="32" data-jdenticon-height="32" data-jdenticon-value="Mark Fisher" /> </a> <div class="s-user-card--info"> <a href="../../users/3578997/mark-fisher" class="s-user-card--link">Mark Fisher</a> <ul class="s-user-card--awards"> <li class="s-user-card--rep" title="reputation score">965</li> <li class="s-award-bling s-award-bling__gold" title="1 gold badge">1</li> <li class="s-award-bling s-award-bling__silver" title="11 silver badge">11</li> <li class="s-award-bling s-award-bling__bronze" title="30 bronze badge">30</li> </ul> </div> </div> </div> </div> </div> </div> <div class="post-layout--right js-post-comments-component"> <div id="comments-63208144" class="comments js-comments-container bt bc-black-075 mt12 " data-post-id="63208144" data-min-length="15"> <ul class="comments-list js-comments-list" data-remaining-comments-count="0" data-canpost="false" data-cansee="true" data-comments-unavailable="false" data-addlink-disabled="true"> <li id="comment-111772807" class="comment js-comment " data-comment-id="111772807" data-comment-owner-id="1038015" data-comment-score="1"> <div class="js-comment-actions comment-actions"> <div class="comment-score js-comment-edit-hide"> <span title="number of 'useful comment' votes received" class="warm">1</span> </div> </div> <div class="comment-text js-comment-text-and-form"> <a name="comment111772807_63208144"></a> <div class="comment-body js-comment-edit-hide"> <span class="comment-copy">desc is the equivalent of alt, not title really.</span> – <a href="../../users/1038015/robert-longson" title="118,664 reputation" class="comment-user ">Robert Longson</a> <span class="comment-date" dir="ltr"><a class="comment-link" href="../../questions/63208144/why-does-a-link-not-take-the-title-of-a-contained-svg-as-it-s-accessible-name#comment111772807_63208144"><span title="2020-08-01T18:50:28.180 License: CC BY-SA 4.0" class="relativetime-clean">Aug 01 '20 at 18:50</span></a></span> </div> </div> </li> <li id="comment-111782597" class="comment js-comment " data-comment-id="111782597" data-comment-owner-id="3578997" data-comment-score="0"> <div class="js-comment-actions comment-actions"> <div class="comment-score js-comment-edit-hide"> </div> </div> <div class="comment-text js-comment-text-and-form"> <a name="comment111782597_63208144"></a> <div class="comment-body js-comment-edit-hide"> <span class="comment-copy">@RobertLongson Ah I see, want to make that into an answer?</span> – <a href="../../users/3578997/mark-fisher" title="965 reputation" class="comment-user owner">Mark Fisher</a> <span class="comment-date" dir="ltr"><a class="comment-link" href="../../questions/63208144/why-does-a-link-not-take-the-title-of-a-contained-svg-as-it-s-accessible-name#comment111782597_63208144"><span title="2020-08-02T10:14:00.450 License: CC BY-SA 4.0" class="relativetime-clean">Aug 02 '20 at 10:14</span></a></span> </div> </div> </li> <li id="comment-111800161" class="comment js-comment " data-comment-id="111800161" data-comment-owner-id="2702894" data-comment-score="0"> <div class="js-comment-actions comment-actions"> <div class="comment-score js-comment-edit-hide"> </div> </div> <div class="comment-text js-comment-text-and-form"> <a name="comment111800161_63208144"></a> <div class="comment-body js-comment-edit-hide"> <span class="comment-copy">@RobertLongson Hi, quick one, can you point me to where that information comes from please? I have for a long time been telling people the exact opposite and if I have been incorrect in that fact I would obviously like to correct my mistake. `title` is meant to be the equivalent of `alt` surely? I added my source to the question below, is there something in the current spec about it as that is from the draft spec? Thanks in advance!</span> – <a href="../../users/2702894/grahamthedev" title="22,724 reputation" class="comment-user ">GrahamTheDev</a> <span class="comment-date" dir="ltr"><a class="comment-link" href="../../questions/63208144/why-does-a-link-not-take-the-title-of-a-contained-svg-as-it-s-accessible-name#comment111800161_63208144"><span title="2020-08-03T06:39:07.083 License: CC BY-SA 4.0" class="relativetime-clean">Aug 03 '20 at 06:39</span></a></span> </div> </div> </li> </ul> </div> </div> </div> </div> <div id="answers"> <a name="tab-top"></a> <div id="answers-header"> <div class="answers-subheader grid ai-center mb8"> <div class="grid--cell fl1"> <h2 class="mb0" data-answercount="9">1 Answers<span style="display:none;" itemprop="answerCount">1</span></h2> </div> </div> </div> <a name="63224571"></a> <div id="answer-63224571" class="answer accepted-answer" data-answerid="63224571" data-ownerid="2702894" data-score="2" itemprop="acceptedAnswer" itemscope="" itemtype="https://schema.org/Answer"> <div class="post-layout"> <div class="votecell post-layout--left"> <div class="js-voting-container grid jc-center fd-column ai-stretch gs4 fc-black-200" data-post-id="63224571"> <button class="js-vote-up-btn grid--cell s-btn s-btn__unset c-pointer"><svg aria-hidden="true" class="m0 svg-icon iconArrowUpLg" width="36" height="36" viewBox="0 0 36 36"><path d="M2 26h32L18 10 2 26z"></path></svg></button> <div class="js-vote-count grid--cell fc-black-500 fs-title grid fd-column ai-center" itemprop="upvoteCount" data-value="2">2</div> <div class="js-accepted-answer-indicator grid--cell fc-green-500 py6 mtn8"><div class="ta-center"><svg aria-hidden="true" class="svg-icon iconCheckmarkLg" width="36" height="36" viewBox="0 0 36 36"><path d="m6 14 8 8L30 6v8L14 30l-8-8v-8z"></path></svg></div></div> </div> </div> <div class="postcell post-layout--right"> <div class="s-prose js-post-body" itemprop="text"><h2>Short Answer</h2> <p>Visually hidden text is still the most robust way to ensure link text is read out.</p> <p>There are other ways of doing this that are neater such as using the <code>alt</code> attribute on an external image or <code>aria-labelledby</code> on an inline SVG so I have included those in the answer below.</p> <h2>Long Answer</h2> <p>Most modern screen readers will not have a problem with this (NVDA and JAWS both read the title text in my quick test) but some older ones (including old versions of NVDA, JAWs etc.) will not work.</p> <p>I believe that the comment that "desc" is the equivalent of "alt" is not correct as I <a href="../../questions/59563251/inline-svg-title-desc-correct-usage-for-accessilibility#59563793">explained in this answer on title vs description on SVG</a> (the first three lines are relevant).</p> <p>To further expand on this here is what the W3C says about SVGs in the proposed spec update:-</p> <blockquote> <p>The ‘title’ child element represents a short text alternative for the element.</p> <p>On a link, this could be the title or a description of the target resource; on an image or drawing object, it could be a short description of the graphic; on interactive content, it could be a label for, or instructions for, use of the element; and so forth.</p> <p>source: <a class="external-link" href="https://www.w3.org/TR/SVG2/struct.html#TitleElement" rel="nofollow noreferrer">https://www.w3.org/TR/SVG2/struct.html#TitleElement</a></p> </blockquote> <blockquote> <p>The ‘desc’ element represents more detailed textual information for the element such as a description. This is typically exposed to assistive technologies to provide more detailed information, such as a description of the visual appearance of a graphic or help to explain the functionality of a complex widget. It is not typically available to other users, so should not be used for essential instructions.</p> <p>source: <a class="external-link" href="https://www.w3.org/TR/SVG2/struct.html#DescElement" rel="nofollow noreferrer">https://www.w3.org/TR/SVG2/struct.html#DescElement</a></p> </blockquote> <h3>External SVGs</h3> <p>For external SVG files the recommended way to ensure text is read is to use <code>alt</code> tags. This may mean slight duplication but alt attributes work back to ie4!</p> <p>Keep your <code>title</code> attribute as if someone accesses the image directly they will still get some description of what the image contains.</p> <h3>Inline SVGs</h3> <p>For this you should give your <code>title</code> an ID. Then add <code>aria-labelledby</code> to the surrounding link. As stated in the question I linked you can also give the <code><description></code> an ID and link both of them if you wish.</p> <p>The downside is that <a class="external-link" href="https://www.powermapper.com/tests/screen-readers/labelling/a-aria-labelledby-img-no-alt/" rel="nofollow noreferrer"><code>aria-labelledby</code> is not as well supported</a> as you might think, but it is perfectly valid and passes WCAG recommendations.</p> <pre><code><a href="/fern"> <svg role="img" viewBox="0 0 100 100" aria-labelledby="linkText"> <title id="linkText">Bracken</title> <use xlink:href="/ferns_sprite.svg#bracken"></use> </svg> </a> </code></pre> <h3>The most robust way - visually hidden text.</h3> <p>The above two ways of doing this are correct, but if you support Internet Explorer (which you should if you care about accessibility as <a class="external-link" href="https://webaim.org/projects/screenreadersurvey8/#browsers" rel="nofollow noreferrer">usage of IE is higher in the screen reader community</a>) then the most robust way is still visually hidden text.</p> <p>Visually hidden text is not visible on the screen but will still be read by a screen reader.</p> <p>Please use the CSS class below to hide text as it has <a href="../../questions/62107074/how-to-hide-a-text-and-make-it-accessible-by-screen-reader#62109988">better compatibility than bootstrap sr-only class as explained in this answer I gave</a>.</p> <p>Notice how I completely hide the SVG in both circumstances using <code>aria-hidden="true"</code> and also add <code>focusable="false"</code> on the inline SVG due to Internet Explorer and older Opera browsers making SVGs interactive. The empty <code>alt=""</code> is still required as a fallback for screen readers that don't fully support <code>aria</code>.</p> <p>The below should work all the way back to IE6 and with the CSS class provided should hopefully work for several years to come!</p> <p></p><div class="snippet" data-babel="false" data-console="true" data-hide="false" data-lang="js"> <div class="snippet-code"> <pre class="snippet-code-css lang-css prettyprint-override"><code>.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 */ }</code></pre> <pre class="snippet-code-html lang-html prettyprint-override"><code><a href="/fern"> <span class="visually-hidden">Bracken</span> <svg role="img" viewBox="0 0 100 100" aria-hidden="true" focusable="false"> <title>Bracken</title> <use xlink:href="/ferns_sprite.svg#bracken"></use> </svg> </a> <a href="/fern"> <span class="visually-hidden">Bracken</span> <img src="/bracken" alt="" aria-hidden="true" /> </a></code></pre> </div> </div> </div> <div class="mb0"> <div class="mt16 grid gs8 gsy fw-wrap jc-end ai-start pt4 mb16"> <div class="grid--cell mr16 fl1 w96"></div> <div class="post-signature grid--cell"> <div class="user-info "> <div class="user-action-time">edited <span title="2020-08-03T07:09:59.797" class="relativetime">Aug 03 '20 at 07:09</span></div> <div class="user-gravatar32"></div> <div class="user-details" itemprop="author" itemscope="" itemtype="http://schema.org/Person"> <span class="d-none" itemprop="name">GrahamTheDev</span> <div class="-flair"></div> </div> </div> </div> <div class="post-signature grid--cell"> <div class="s-user-card s-user-card"> <time class="s-user-card--time" datetime="answered Aug 03 '20 at 06:15">answered Aug 03 '20 at 06:15</time> <a href="../../users/2702894/grahamthedev" class="s-avatar s-avatar__32 s-user-card--avatar"> <img class="s-avatar--image" src="../../users/profiles/2702894.webp" data-jdenticon-width="32" data-jdenticon-height="32" data-jdenticon-value="GrahamTheDev" /> </a> <div class="s-user-card--info"> <a href="../../users/2702894/grahamthedev" class="s-user-card--link">GrahamTheDev</a> <ul class="s-user-card--awards"> <li class="s-user-card--rep" title="reputation score">22,724</li> <li class="s-award-bling s-award-bling__gold" title="2 gold badges">2</li> <li class="s-award-bling s-award-bling__silver" title="32 silver badges">32</li> <li class="s-award-bling s-award-bling__bronze" title="64 bronze badges">64</li> </ul> </div> </div> </div> </div> </div> </div> <div class="post-layout--right js-post-comments-component"> </div> </div> </div> </div> </div> <div id="sidebar" class="show-votes" role="complementary" aria-label="sidebar"> <div class="module sidebar-linked"> <h4 id="h-linked">Linked</h4> <div class="linked"> <div class="spacer"> <a title="Vote score (upvotes - downvotes)"><div class="answer-votes answered-accepted default">6</div></a> <a href="../../questions/65257333/svg-inside-h1-tag" class="question-hyperlink">Svg inside h1 tag</a> </div> </div> </div> </div> </div> </div> <script src="../../static/js/stack-icons.js"></script> <script src="../../static/js/fromnow.js"></script> </body> </html>