<p class="deck"> A few months ago I teamed up with <a href="https://superfriend.ly/">SuperFriendly</a> to <a href="https://www.sarasoueidan.com/work/khan-academy-2018-annual-report">create an accessible micro-site</a> for the <a href="https://khanacademyannualreport.org/">Khan Academy 2018 Annual Report</a>. The site is a very beautiful visual representation of Khan’s real-life impact on world education, their end-of-year financial reports, and more. By nature, the annual report contains a <em>lot</em> of data and visualizations and charts to represent it. My mission was to make sure that the way this data is presented and implemented is as accessible to site’s visitors as possible, regardless of how they explore the site. </p> <p> Data visualizations are a great way to make information stand out and sometimes a lot easier to parse and understand. But they also come with their own accessibility challenges that you need to be aware of. </p> <figure role="figure" aria-label="The Khan Academy annual report represented all of the main data showcasing the impact they had on world education using different kinds of charts — simple and complex." class="wide"> <img src="https://www.sarasoueidan.com/assets/images/work/khan-academy/khan-academy-chart.png" alt="An example of a chart from the Khan Academy 2018 Annual Report. Screenshot." /> <figcaption> <a href="https://khanacademyannualreport.org/">The Khan Academy annual report</a> represented all of the main data showcasing the impact they had on world education using different kinds of charts — simple and complex. </figcaption> </figure> <p>When it comes to visualizing data on the Web, SVG is the most used format. It is perfect for creating data visualizations because it comes with all the elements needed to create the shapes used to represent information. Because SVG is an XML format, similar to HTML, it comes with a lot of tags to represent different kinds of elements, mostly shapes. We have <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/BasicShapes">elements for creating basic shapes</a> such as <code>circle</code> s, <code>ellipse</code> s, <code>rect</code> angles, <code>polygon</code> s, <code>polyline</code> s, <code>line</code> s, and more complex <code>path</code> s, all of which are used to draw all kinds of data charts and visualizations.</p> <p>And often times, these charts and visualizations are also animated and interactive; and SVG provides us with the ability to animate and interact with the images we create with it — using CSS and JavaScript.</p> <p>But SVG data visualizations are, at the end of the day, SVG <em>images</em>. This means that when a screen reader comes across one, it is likely going to announce it the same way it would announce any image: as an image, with an accessible name (because I’m assuming that the image <em>does</em> have an accessible name provided in the <code>alt</code> attribute). This, in turn, means that the screen reader is not going to announce the content presented <em>inside</em> the chart to the user by default. It is only going to announce whatever accessible name we provide it with. Making sure it announces the content inside the image is something that requires a little more work on our side.</p> <h3 id="how-accessible-are-svg-data-visualizations-%26-charts%3F" tabindex="-1">How accessible <em>are</em> SVG data visualizations & charts?</h3> <p>Albeit being a perfect candidate for <em>visually</em> representing information, SVG is not equipped with the semantics needed to convey <em>the content</em> of that information to the user.</p> <p>In <a href="https://tink.uk/accessible-svg-line-graphs/">her article about creating accessible line graphs with SVG</a>, Léonie Watson says:</p> <blockquote> <p>“SVG is often used for data visualisation, but because SVG lacks the semantics to express structures like bar charts, line graphs, and scatter plots, the content is difficult for screen reader users to interpret.”</p> </blockquote> <p>Léonie wrote a few articles about making content inside SVG accessible that I will link to at the bottom of this article. The concept in all of them is the same: use some of the available ARIA roles to modify the semantics of SVG elements to be announced to screen readers as something other than what they are.</p> <blockquote> SVG has no native semantics for representing structures like tables, but ARIA1.1 introduces a number of roles that can be used to polyfill the necessary semantic information. <cite>— Léonie Watson, <a href="https://tink.uk/accessible-svg-tables/">Accessible SVG Tables</a></cite> </blockquote> <p>For example, in her article, she uses the ARIA table attributes to announce a visual line graph as a table to screen reader users, which makes it possible for them to announce the data inside those tables to their users as well. This is possible because a table is often times an appropriate alternative way to represent the information in a line graph.</p> <p>But Léonie finally notes (and emphasis is mine here) that:</p> <blockquote> <p>“The state of SVG accessibility support in browsers and screen readers is still highly inconsistent, even when ARIA is used to polyfill semantic information.</p> <p>The upshot is that this technique is enough to make the primary SVG content more screen reader accessible […] but it isn’t enough to make it completely so. For this (and many other good reasons), <strong>it’s a good idea to provide an alternative view of the information</strong>, for example by providing both a graphical and a tabular view of the content”</p> </blockquote> <p>Personally, I’d avoid hacking my way around making an SVG chart accessible using ARIA roles. Most of the charts in the Khan Academy annual report were more complex, so using ARIA roles to change their semantics would not only prove to be counter-productive, but also risky, especially given how inconsistent screen reader and browser support is, and how important those charts are for the site’s visitors.</p> <p>So, I chose the alternative view of the information route. And with all the different SVG embedding techniques available to use, SVG makes all kinds of fallbacks easy to implement.</p> <h3 id="choosing-the-most-appropriate-svg-embedding-technique" tabindex="-1">Choosing the most appropriate SVG embedding technique</h3> <p>There are 6 ways to embed an SVG on a Web page. Choosing the most appropriate one highly depends on your requirements and what you need the SVG to be capable of <em>and</em> the kind of fallback that you need.</p> <ul> <li>For data visualizations and infographics, it’s usually best to provide the plain text (or table) version of the content of the image as fallback. Since that text fallback is likely to be more than one or two sentences long, we need to embed the SVG using an embedding technique that caters for that.</li> <li>We were also planning on animating the charts had the project timeframe allowed it. This means that the embedding technique also needs to allow that.</li> <li><em>And</em> I know that we will need JavaScript for the animation, which also narrows down my embedding options further.</li> </ul> <p><code><iframe></code> , <code><object></code> and inline <code><svg></code> all tick all of the above boxes.</p> <p>I’m not a big fan of <code><iframe></code> s, and <code><object></code> already gives me everything I need that <code><iframe></code> does, so, out of these two, I always choose <code><object></code> .</p> <p>In addition to the above requirements, I had a couple of other considerations in mind:</p> <ul> <li>we have a <em>lot</em> of charts, especially on the <a href="https://khanacademyannualreport.org/leveling-the-playing-field/#introduction">leveling the playing field</a> page,</li> <li>and some of those charts are quite larger than the others. So I’ll want to keep page load and performance in mind.</li> </ul> <p>If I were to embed the charts inline, they would “pollute” my HTML, and would not be cached unless the whole page is. That’s not ideal. Whereas an <code><object></code> would reference an external SVG image which, after the first request, would then be cached, making subsequent visits faster.</p> <p>Also, on a more design-related note: I was working with SVG images exported from Adobe Illustrator, which tends to repeatedly create and use the same IDs and CSS class names for the images it exports. If I were to embed all of the images inline, the IDs and class names would clash and I would need to spend time I didn’t have to go over each SVG and provide it with unique class names to avoid the style inheritance nightmare, because, by default:</p> <blockquote> <p>Styles within an inline <code><svg></code> are not scoped to it.</p> </blockquote> <p>This means that if you have two inline <code>svg</code> s on the page, the styles from the second SVG in the DOM order will override the styles in the first one for elements with shared class names.</p> <p>And last but not least, I love the clean and uncluttered way that <code><object></code> enables me to provide text fallback for my SVG images: simply place the text fallback in between the opening and closing <code>object</code> tags, and that text will be displayed wherever SVG is not supported and/or whenever the SVG fails to load.</p> <p>So, <code><object></code> it is.</p> <h3 id="embedding-the-charts" tabindex="-1">Embedding the charts</h3> <p>The initial base code for one of the simple charts would then look like this:</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>object</span><br /><span class="highlight-line"></span><br /> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image/svg+xml<span class="token punctuation">"</span></span> <span class="token attr-name">data</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/images/longbeach.svg<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>Khan Academy math usage for 30 minutes per week proved to </span><br /><span class="highlight-line"> improve more than 5,000 Long Beach students scores by 2 times </span><br /><span class="highlight-line"> in the Smarter Balanced Assessment.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>object</span><span class="token punctuation">></span></span> </span></code></pre> <p>This was just the base markup, but I was curious enough to check how it would be announced by a screen reader. I’m on macOS so I usually test my work with VoiceOver (VO) on Safari.</p> <p>VO announced the chart as a frame, and used the file name of the SVG (in this case <code>longbeach.svg</code> ) as the accessible name for it. Ouch.</p> <p>I was expecting the random name situation since my markup doesn’t yet include a label for the image, but I didn’t know how an <code>object</code> is usually announced. I was also curious if VO would <em>somehow</em> recognize or find the fallback text and announce it. It didn’t. Now, it was time to start “fixing” the situation.</p> <p>I want my chart to be announced as an image to start, so I needed to modify its semantics using ARIA <code>role</code> . To give it an accessible name, I used <code>aria-label</code> :</p> <pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>object</span><br /><span class="highlight-line"> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>img<span class="token punctuation">"</span></span> </span><br /><span class="highlight-line"> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span>“Khan</span> <span class="token attr-name">Academy</span> <span class="token attr-name">Math</span> <span class="token attr-name">usage</span> <span class="token attr-name">level</span> <span class="token attr-name">in</span> <span class="token attr-name">Long</span> <span class="token attr-name">Beach.</span> <span class="token attr-name">Chart."</span></span><br /><span class="highlight-line"></span><br /> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image/svg+xml<span class="token punctuation">"</span></span> <span class="token attr-name">data</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/images/longbeach.svg<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>Khan Academy math usage for 30 minutes per week proved to </span><br /><span class="highlight-line"> improve more than 5,000 Long Beach students scores by 2 times </span><br /><span class="highlight-line"> in the Smarter Balanced Assessment.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>object</span><span class="token punctuation">></span></span> </span></code></pre> <p>With these two attributes added, VO communicated my chart as an image, and used the label I gave it as its accessible name. Great.</p> <p>But a visitor using VO would now know that there is a chart showing Math usage levels in Long Beach, but they would not be able to access the data inside that chart.</p> <p>Since I already have a text fallback clearly describing the data in the chart right there in my markup, I thought I could use that instead of try to communicate the same content in a second way. That text fallback was not being exposed to my screen reader. In other words, it was <em>hidden</em> from screen readers.</p> <p>But I already know that I can expose hidden content to my screen reader to announce if I reference that content inside of <code>aria-labelledby</code> . I’ve used this in <a href="https://www.sarasoueidan.com/blog/accessible-icon-buttons">my previous article</a> to provide a visually-hidden accessible label to an icon-only button. So it makes sense that I’d be able to do the same using <code>aria-describedby</code> .</p> <p>There are several reasons why I’d want the image’s text content exposed using <code>aria-describedby</code> not <code>aria-labelledby</code> :</p> <ul> <li><code>aria-labelledby</code> is used to provide an accessible label to an element. My image already has one that I have provided in <code>aria-label</code> .</li> <li>The text content is used to <em>describe</em> the (content of) the image.</li> <li>An accessible name (label) should be short and succinct. A description is usually longer, especially (and particularly) in the case of text (or table!) provided for charts and visualizations.</li> <li>And, last but not least, I want the text content to be announced after the image and its accessible name are. That’s exactly what <code>aria-describedby</code> does.</li> </ul> <blockquote> There is a major difference between the way the content referenced in <code>aria-labelledby</code> is announced versus that referenced in <code>aria-describedby</code>. The accessible name is announced <em>before</em> the image’s role is announced (in VO, at least); the description is announced <em>after</em> the image’s role, <strong>with a short pause preceding it</strong>. </blockquote> <p>That’s exactly how I want my text to be announced. So, with all that taken into account, the final code for my chart looks like this:</p> <pre class="language-html"><code class="language-html"><span class="highlight-line">< object</span><br /><span class="highlight-line"> role="img" </span><br /><span class="highlight-line"> aria-label=“Khan Academy Math usage level in Long Beach. Chart."</span><br /><span class="highlight-line"> aria-describedby="longbeachdesc"</span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> type="image/svg+xml" data="/images/longbeach.svg"></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>longbeachdesc<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Khan Academy math usage for 30 minutes per week proved to </span><br /><span class="highlight-line"> improve more than 5,000 Long Beach students scores by 2 times </span><br /><span class="highlight-line"> in the Smarter Balanced Assessment.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line">< /object> </span></code></pre> <p>This works very well, including for images that have longer descriptions. Of course, we made sure (thanks, Jessi) that the descriptions were as concise and succinct as possible, so the user is not overwhelmed with long announcements but would still get a very clear and accurate text version of the information provided in each chart.</p> <h3 id="%E2%80%9Ccan%E2%80%99t-you-just-use-%3Cfigure%3E-for-the-charts%3F%E2%80%9D" tabindex="-1">“Can’t you just use <code><figure></code> for the charts?”</h3> <p>I got this question a couple of times after speaking about my implementation choice above — once during a workshop, and once after a talk.</p> <p>I’m guessing that the idea here is that you would implement the SVG chart in an <code>img</code> inside a <code>figure</code> and use the <code>figure</code> ’s <code>figcaption</code> to provide the text alternative of the chart’s content to screen reader users. I assume the suggestion would be to hide the figcaption in this case visually (because we don’t show it visually, of course) and make it available to screen readers only, using a utility class such as <code>sr-only</code> .</p> <pre class="language-html"><code class="language-html"><span class="highlight-line">< !-- This is what you should NOT do.--> </span><br /><span class="highlight-line">< figure> </span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/path/to/chart.svg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ACCESSIBLECHARTTITLE<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>figcaption</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sr-only<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>Here goes the text that describes the information inside the chart.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>Note that this text could be a couple of a few paragprahs long.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>It might even be appropriate to represent the data using a table!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>figcaption</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line">< /figure> </span></code></pre> <pre class="language-css"><code class="language-css"><span class="token comment">/* <br /><span class="highlight-line"> * Utility class to hide content visually while keeping it screen reader-accessible.</span><br /><span class="highlight-line"> * Source: https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html </span><br /> */</span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token selector">.sr-only:not(:focus):not(:active)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">clip</span><span class="token punctuation">:</span> <span class="token function">rect</span><span class="token punctuation">(</span>0 0 0 0<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><br /><span class="highlight-line"> <span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">inset</span><span class="token punctuation">(</span>100%<span class="token punctuation">)</span><span class="token punctuation">;</span> </span><br /><span class="highlight-line"> <span class="token property">height</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span> </span><br /><span class="highlight-line"> <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> </span><br /><span class="highlight-line"> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span> </span><br /><span class="highlight-line"> <span class="token property">white-space</span><span class="token punctuation">:</span> nowrap<span class="token punctuation">;</span> </span><br /><span class="highlight-line"> <span class="token property">width</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span> </span><br /><span class="highlight-line"><span class="token punctuation">}</span></span></code></pre> <p>This approach has more than one issue.</p> <ul> <li> <p>I didn’t choose <code><figure></code> because I excluded all SVG embedding options that don’t allow the SVG charts to be animated. <code><figure></code> is static — meaning that it won’t allow the would-be SVG <code>img</code> inside of it to be animated.</p> </li> <li> <p>I also didn’t consider <code><figure></code> as an option because a <code>figure</code> is, by definition, meant to be a meaningful wrapper for a piece of content that is relevant to the current document, but not vital to its understanding.</p> </li> </ul> <blockquote> <p>[The <code>figure</code> element] can thus be used to annotate illustrations, diagrams, photos, code listings, etc, that are referred to from the main content of the document, but that could, without affecting the flow of the document, be moved away from that primary content, ... </p> <cite>— <a href="https://www.w3.org/TR/2011/WD-html5-author-20110809/the-figure-element.html">HTML5: Edition for Web Authors</a></cite> </blockquote> <p>Khan Academy’s annual report charts <em>are</em> vital to the understanding of the page they’re in, and <em>cannot</em> be removed from the primary document without affecting it. The data inside these charts <em>is</em> the meat of the annual report.</p> <p>So, as far as semantics are concerned, <code>figure</code> is not an element suitable to represent these charts.</p> <ul> <li>The <code>figure</code> ’s <code>figcaption</code> is used by screen readers as <strong>the accessible name</strong> of the <code>figure</code> _. As I mentioned earlier, the text fallback for the charts is <em>not</em> meant to be used as a name (label), and it should be announced as a <em>description</em>, not a name.</li> </ul> <p>Furthermore, the markup for the figure would have to be very dirty even if using it <em>were</em> possible, because the text that goes in the <code>figcaption</code> needs to be provided inside an <code>aria-label</code> on the <code>figure</code> alongside a <code>role</code> attribute for certain browser-screen-reader combinations to even announce <code>figure</code> as it is intended to be announced; and this brings us again to the “but the text inside <code>figcaption</code> is not even a label for the <code>figure</code> element” argument…</p> <p>My friend <a href="https://twitter.com/scottohara">Scott O’Hara</a> has <a href="https://www.scottohara.me/blog/2019/01/21/how-do-you-figure.html">a wonderful article</a> about <code>figure</code> and <code>figcaption</code> detailing how to use and <em>not</em> use them, and how to ensure the best cross-browser and screen reader compatibility. I highly recommend checking it out.</p> <p>When it comes to accessibility, semantics matter <em>a lot</em>. Learning about an element’s semantics and proper usage helps us make better informed decisions as to which element to use when.</p> <h3 id="final-words" tabindex="-1">Final Words</h3> <p>I had great fun working on the Khan Academy annual report, and I learned quite a bit in the process. Khan Academy’s mission is to provide free education for everyone everywhere. In other words, they are working to make world-class education <em>accessible</em> by everyone. The least I could do is to make sure the product I helped build for them was just as accessible by everyone, regardless of their context and abilities. I’m quite proud of the work we did. And if you could use my help building better, more accessible products, <a href="https://www.sarasoueidan.com/contact/">get in touch</a>.</p> <p>And if you want to be the first to know when the next article comes out (hint: there will be more like this one), you can <a href="http://sarasoueidan.com/blog/index.xml">subscribe to my blog’s RSS feed</a>.</p> <p>Thank you for reading.</p> <h3 id="further-reading" tabindex="-1">Further Reading</h3> <ul> <li><a href="https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html">Inclusively Hidden</a></li> <li><a href="https://www.scottohara.me/blog/2019/01/21/how-do-you-figure.html">How do you figure?</a></li> <li><a href="https://tink.uk/accessible-svg-tables/">Accessible SVG Tables</a></li> <li><a href="https://tink.uk/accessible-svg-line-graphs/">Accessible SVG Line Graphs</a></li> <li><a href="https://tink.uk/accessible-svg-flowcharts/">Accessible SVG Flowcharts</a></li> </ul>