html icon indicating copy to clipboard operation
html copied to clipboard

Review accessibility of the content models venn diagram

Open zcorpan opened this issue 3 years ago • 2 comments

https://html.spec.whatwg.org/multipage/dom.html#kinds-of-content has an SVG venn diagram (under "These categories are related as follows:"), where you can hover over the circles to reveal text next to the diagram.

The "alt text" is the 2 paragraphs following the diagram (for how the categories overlap), and the remaining subsections (for the list of elements in each category). So no information is technically inaccessible even if the venn diagram doesn't load.

However, I think it doesn't follow that we're all good, necessarily. The popup on hover only works for users with a pointing device, but could be useful for all users. Making the circles focusable could help.

Showing text on hover and hiding it when no longer hovering might not be so great, for example if you rely on a magnifying glass AT to be able to read text (or maybe you prefer to hover the text that you're reading). Being able to click the circles to make the text stay put seems better.

We can also check the experience with a screen reader.

zcorpan avatar Jul 06 '22 10:07 zcorpan

Good question! Strictly speaking, the prose in the following two paragraphs provides all the pertinent information available in the venn diagram, so you could get away with simply using aria-describedby="the ids of the following two paragraphs", and that would indicate to AT users that the visible text is an adequate text alternative.

Content only on hover is a WCAG violation though, so that will probably need some attention. It's worth reading https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus for more detail. The main issue is the the content shouldn't disappear automatically when the pointer moves off the hover area, and there are many ways to meet that goal.

I notice that the SVG is inside an iframe (is that strictly necessary?) - there may be a need for a title attribute for the iframe.

For further polish, some aria can be applied within the SVG, so I'm thinking that each <g> representing an oval could have role="img" and an aria-label with a finer grained textual expression for each subset such as "Embedded - a subset of phrasing content. May be interactive.".

These same <g> elements could very usefully have aria-describedby pointing at the id of the content which appears on hover. An even better choice in the near future may be the forthcoming aria-details - draft spec is available at https://w3c.github.io/aria/#aria-details ).

brennanyoung avatar Jul 20 '22 14:07 brennanyoung

It could be inline SVG instead of in an iframe, but it can't be referenced with img because then hover doesn't work.

zcorpan avatar Aug 09 '22 10:08 zcorpan

Try this with a screen reader. Notice the "graphics-document" and "graphics-object" roles, the tabindex attribute, and the use of aria-labelledby and aria-describedby. Still some room for improvement - ideally the lists should be pointed at by aria-details, but that is still a draft spec at time of writing.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="-250 -150 1000 288" role="graphics-document">
<style type="text/css">
 svg     { font: bold 18px sans-serif; text-anchor: middle; }
 ellipse { fill: #3c790a; stroke: #000000; opacity: 0.67; }
 text    { fill: #ffffff; pointer-events: none; }
 ellipse:hover { stroke-width: 5px; }
 g > foreignObject { display: none; }
 g:focus {outline-width:0;}
 g:focus > ellipse { stroke-width: 5px;}
 g:focus > ellipse + foreignObject, g:hover > ellipse + foreignObject { display: block; }
 foreignObject {background-color:white	;}
 div { font: 14px sans-serif; }
 h1 { margin: 0 0 0.25em 0; padding: 0; font: 900 27px sans-serif; }
 ul { margin: 0; padding: 0 0 0 1em; }
 li { display: inline; margin: 0; padding: 0; line-height: 1.5; }
 li:not(:last-child):after { content: ', '; }
 span { font: italic 14px sans-serif; }
 code { font: 1em monospace; color: #CE3C05; }
 p { margin: 0.75em 0 0 0; padding: 0 0 0 1em; font: italic 14px sans-serif; }
</style>
<g role="graphics-object" tabindex="0" class="a" transform="translate(2, -3)" aria-labelledby="flow_name" aria-describedby="flow">
 <ellipse rx="244" ry="132"/>
 <foreignObject x="250" y="-150" width="500" height="288" transform="translate(-2, 3)">
  <div xmlns="http://www.w3.org/1999/xhtml">
   <h1 id="flow_name">Flow content</h1>
   <ul id="flow">
    <li><code>a</code></li>
    <li><code>abbr</code></li>
    <li><code>address</code></li>
    <li><code>area</code>*</li>
    <li><code>article</code></li>
    <li><code>aside</code></li>
    <li><code>audio</code></li>
    <li><code>b</code></li>
    <li><code>bdi</code></li>
    <li><code>bdo</code></li>
    <li><code>blockquote</code></li>
    <li><code>br</code></li>
    <li><code>button</code></li>
    <li><code>canvas</code></li>
    <li><code>cite</code></li>
    <li><code>code</code></li>
    <li><code>data</code></li>
    <li><code>date</code></li>
    <li><code>datalist</code></li>
    <li><code>del</code></li>
    <li><code>details</code></li>
    <li><code>dfn</code></li>
    <li><code>dialog</code></li>
    <li><code>div</code></li>
    <li><code>dl</code></li>
    <li><code>em</code></li>
    <li><code>embed</code></li>
    <li><code>fieldset</code></li>
    <li><code>figure</code></li>
    <li><code>footer</code></li>
    <li><code>form</code></li>
    <li><code>h1</code></li>
    <li><code>h2</code></li>
    <li><code>h3</code></li>
    <li><code>h4</code></li>
    <li><code>h5</code></li>
    <li><code>h6</code></li>
    <li><code>header</code></li>
    <li><code>hgroup</code></li>
    <li><code>hr</code></li>
    <li><code>i</code></li>
    <li><code>iframe</code></li>
    <li><code>img</code></li>
    <li><code>input</code></li>
    <li><code>ins</code></li>
    <li><code>kbd</code></li>
    <li><code>keygen</code></li>
    <li><code>label</code></li>
    <li><code>link</code>*</li>
    <li><code>main</code>*</li>
    <li><code>map</code></li>
    <li><code>mark</code></li>
    <li><code>math</code></li>
    <li><code>menu</code></li>
    <li><code>meta</code>*</li>
    <li><code>meter</code></li>
    <li><code>nav</code></li>
    <li><code>noscript</code></li>
    <li><code>object</code></li>
    <li><code>ol</code></li>
    <li><code>output</code></li>
    <li><code>p</code></li>
    <li><code>picture</code></li>
    <li><code>pre</code></li>
    <li><code>progress</code></li>
    <li><code>q</code></li>
    <li><code>ruby</code></li>
    <li><code>s</code></li>
    <li><code>samp</code></li>
    <li><code>script</code></li>
    <li><code>search</code></li>
    <li><code>section</code></li>
    <li><code>select</code></li>
    <li><code>slot</code></li>
    <li><code>small</code></li>
    <li><code>span</code></li>
    <li><code>strong</code></li>
    <li><code>sub</code></li>
    <li><code>sup</code></li>
    <li><code>svg</code></li>
    <li><code>table</code></li>
    <li><code>template</code></li>
    <li><code>textarea</code></li>
    <li><code>time</code></li>
    <li><code>u</code></li>
    <li><code>ul</code></li>
    <li><code>var</code></li>
    <li><code>video</code></li>
    <li><code>wbr</code></li>
    <li><span>autonomous custom elements</span></li>
    <li><span>Text*</span></li>
   </ul>
   <p>* Under certain circumstances (see prose).</p>
  </div>
 </foreignObject>
 <text x="10" y="-94">Flow</text>
</g>
<g role="graphics-object" tabindex="0" class="b" transform="translate(127, -48.5)" aria-labelledby="heading_name" aria-describedby="heading">
 <ellipse rx="75" ry="42.5"/>
 <foreignObject x="250" y="-150" width="500" height="288" transform="translate(-127, 48.5)">
  <div xmlns="http://www.w3.org/1999/xhtml">
   <h1 id="heading_name">Heading content</h1>
   <ul id="heading">
    <li><code>h1</code></li>
    <li><code>h2</code></li>
    <li><code>h3</code></li>
    <li><code>h4</code></li>
    <li><code>h5</code></li>
    <li><code>h6</code></li>
    <li><code>hgroup</code></li>
   </ul>
  </div>
 </foreignObject>
 <text x="2" y="6">Heading</text>
</g>
<g role="graphics-object" tabindex="0" class="c" transform="translate(125, 42)" aria-labelledby="sectioning_name" aria-describedby="sectioning">
 <ellipse rx="75" ry="42.5"/>
 <foreignObject x="250" y="-150" width="500" height="288" transform="translate(-125, -42)">
  <div xmlns="http://www.w3.org/1999/xhtml">
   <h1 id="sectioning_name">Sectioning content</h1>
   <ul id="sectioning">
    <li><code>article</code></li>
    <li><code>aside</code></li>
    <li><code>nav</code></li>
    <li><code>section</code></li>
   </ul>
  </div>
 </foreignObject>
 <text x="1" y="5">Sectioning</text>
</g>
<g role="graphics-object" tabindex="0" class="d" transform="translate(-113, 78)" aria-labelledby="metadata_name" aria-describedby="metadata">
 <ellipse rx="117" ry="47" transform="rotate(-15)"/>
 <foreignObject x="250" y="-150" width="500" height="288" transform="translate(113, -78)">
  <div xmlns="http://www.w3.org/1999/xhtml">
   <h1 id="metadata_name">Metadata content</h1>
   <ul id="metadata">
    <li><code>base</code></li>
    <li><code>link</code></li>
    <li><code>meta</code></li>
    <li><code>noscript</code></li>
    <li><code>script</code></li>
    <li><code>style</code></li>
    <li><code>template</code></li>
    <li><code>title</code></li>
   </ul>
  </div>
 </foreignObject>
 <text x="-4" y="8">Metadata</text>
</g>
<g role="graphics-object" tabindex="0" class="e" transform="translate(-128, -34)" aria-labelledby="interactive_name" aria-describedby="interactive">
 <ellipse rx="94" ry="51"/>
 <foreignObject x="250" y="-150" width="500" height="288" transform="translate(128, 34)">
  <div xmlns="http://www.w3.org/1999/xhtml">
   <h1 id="interactive_name">Interactive content</h1>
   <ul id="interactive">
    <li><code>a</code>*</li>
    <li><code>audio</code>*</li>
    <li><code>button</code></li>
    <li><code>details</code></li>
    <li><code>embed</code></li>
    <li><code>iframe</code></li>
    <li><code>img</code>*</li>
    <li><code>input</code>*</li>
    <li><code>keygen</code></li>
    <li><code>label</code></li>
    <li><code>object</code>*</li>
    <li><code>select</code></li>
    <li><code>textarea</code></li>
    <li><code>video</code>*</li>
   </ul>
   <p>* Under certain circumstances.</p>
  </div>
 </foreignObject>
 <text x="-36" y="5">Interactive</text>
</g>
<g role="graphics-object" tabindex="0" class="f" transform="translate(-40.5, -5)" aria-labelledby="phrasing_name" aria-describedby="phrasing">
 <ellipse rx="76.5" ry="80"/>
 <foreignObject x="250" y="-150" width="500" height="288" transform="translate(40.5, 5)">
  <div xmlns="http://www.w3.org/1999/xhtml">
   <h1 id="phrasing_name">Phrasing content</h1>
   <ul id="phrasing">
    <li><code>a</code>*</li>
    <li><code>abbr</code></li>
    <li><code>area</code>*</li>
    <li><code>audio</code></li>
    <li><code>b</code></li>
    <li><code>bdi</code></li>
    <li><code>bdo</code></li>
    <li><code>br</code></li>
    <li><code>button</code></li>
    <li><code>canvas</code></li>
    <li><code>cite</code></li>
    <li><code>code</code></li>
    <li><code>data</code></li>
    <li><code>date</code></li>
    <li><code>datalist</code></li>
    <li><code>del</code>*</li>
    <li><code>dfn</code></li>
    <li><code>em</code></li>
    <li><code>embed</code></li>
    <li><code>i</code></li>
    <li><code>iframe</code></li>
    <li><code>img</code></li>
    <li><code>input</code></li>
    <li><code>ins</code>*</li>
    <li><code>kbd</code></li>
    <li><code>keygen</code></li>
    <li><code>label</code></li>
    <li><code>link</code>*</li>
    <li><code>map</code>*</li>
    <li><code>mark</code></li>
    <li><code>math</code></li>
    <li><code>meta</code>*</li>
    <li><code>meter</code></li>
    <li><code>noscript</code></li>
    <li><code>object</code></li>
    <li><code>output</code></li>
    <li><code>picture</code></li>
    <li><code>progress</code></li>
    <li><code>q</code></li>
    <li><code>ruby</code></li>
    <li><code>s</code></li>
    <li><code>samp</code></li>
    <li><code>script</code></li>
    <li><code>select</code></li>
    <li><code>slot</code></li>
    <li><code>small</code></li>
    <li><code>span</code></li>
    <li><code>strong</code></li>
    <li><code>sub</code></li>
    <li><code>sup</code></li>
    <li><code>svg</code></li>
    <li><code>template</code></li>
    <li><code>textarea</code></li>
    <li><code>time</code></li>
    <li><code>u</code></li>
    <li><code>var</code></li>
    <li><code>video</code></li>
    <li><code>wbr</code></li>
    <li><span>autonomous custom elements</span></li>
    <li><span title="text content">Text</span>*</li>
   </ul>
   <p>* Under certain circumstances; see prose.</p>
  </div>
 </foreignObject>
 <text x="0" y="-39.5">Phrasing</text>
</g>
<g role="graphics-object" tabindex="0" class="g" transform="translate(-42, -7)" aria-labelledby="heading_name" aria-describedby="heading">
 <ellipse rx="68" ry="22.5"/>
 <foreignObject x="250" y="-150" width="500" height="288" transform="translate(42, 7)">
  <div xmlns="http://www.w3.org/1999/xhtml">
   <h1 id="embedded_name">Embedded content</h1>
   <ul id="embedded">
    <li><code>audio</code></li>
    <li><code>canvas</code></li>
    <li><code>embed</code></li>
    <li><code>iframe</code></li>
    <li><code>img</code></li>
    <li><code>math</code></li>
    <li><code>object</code></li>
    <li><code>picture</code></li>
    <li><code>svg</code></li>
    <li><code>video</code></li>
   </ul>
  </div>
 </foreignObject>
 <text x="0" y="7">Embedded</text>
</g>
</svg>

brennanyoung avatar Oct 17 '23 15:10 brennanyoung