UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

114 lines (107 loc) 7.9 kB
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE html><html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>A Little Help: WAI-ARIA</title> <link rel="stylesheet" type="text/css" href="css/epub.css" /> <meta name="dat-origPath" value="/html/body/section" /><link rel="prev" href="./ch03s05_3.html" /><link rel="next" href="./ch03s05_5.html" /></head><body> <p data-origPath="/html/body/section/section[1]/p[26]">In many situations, too, a single control would not be made directly accessible. The element that contains all the controls would be the accessible element, as in the following example:</p> <pre class="screen" data-origPath="/html/body/section/section[1]/pre[4]">&lt;div role="group" tabindex="0"&gt; &lt;img role="button" … /&gt; &lt;img role="button" … /&gt; &lt;/div&gt;</pre> <p data-origPath="/html/body/section/section[1]/p[27]">Access to the individual controls inside the grouping <code class="literal">div</code> would be script-enabled. This would allow the reader to quickly skip past the control set if they aren’t interested in what it does (otherwise they would have to tab through every control inside it).</p> <aside class="note" title="Note" data-origPath="/html/body/section/section[1]/aside[5]"> <h3 class="title">Note</h3> <p>See the HTML5 specification for more information on <a class="ulink" href="http://dev.w3.org/html5/spec/Overview.html#attr-tabindex" target="_top">how this attribute works</a>.</p> </aside> <p data-origPath="/html/body/section/section[1]/p[28]">A last note for this section concerns event handlers. Events are what are used to trigger script actions (<code class="literal">onclick</code>, <code class="literal">onblur</code>, etc.). How you wire up your events can impact on the ability of the reader to access your controls, and can lead to keyboard traps (i.e., the inability to leave the control), so you need to pay attention to how you add them.</p> <p data-origPath="/html/body/section/section[1]/p[29]">We could add an <code class="literal">onclick</code> event to our image button to start playback as follows:</p> <pre class="screen" data-origPath="/html/body/section/section[1]/pre[5]">&lt;img src="controls/start.png" id="audio-start" alt="Start" role="button" tabindex="0" onclick="startPlayback('audio01')"/&gt;</pre> <p data-origPath="/html/body/section/section[1]/p[30]">But, if we’d accidentally forgotten the <code class="literal">tabindex</code> attribute, a reader navigating by keyboard would not have been able to find or access this control. Even though <code class="literal">onclick</code> is considered a device-independent event, if the reader cannot reach the element they cannot use the Enter key to activate it, effectively hiding the functionality from them.</p> <p data-origPath="/html/body/section/section[1]/p[31]">You should always ensure that actions can be triggered in a device-independent manner, even if that means repeating your script call in more than one event type. Don’t rely on any of your readers using a mouse, for example.</p> <p data-origPath="/html/body/section/section[1]/p[32]">But again, it pays to engage people who can test your content in real-world scenarios to help discover these issues than to hope you’ve thought of everything.</p> <h3 class="title" id="_forms" data-origPath="/html/body/section/section[2]/h3">Forms</h3> <p data-origPath="/html/body/section/section[2]/p[1]">Having covered how to create custom controls, we’ll now turn to forms, which are another common problem area ARIA helps address. To repeat myself for a moment, though, the first best practice when creating forms is to always use the native form elements that HTML5 provides. See the last section again for why rolling your own is not a good idea.</p> <p data-origPath="/html/body/section/section[2]/p[2]">When it comes to implementing forms, the logical ordering of elements is one key to simplifying access and comprehension. The use of <code class="literal">tabindex</code> can help to correct navigation, as we just covered, but it’s better to ensure your form is logically navigable in the first place. Group form fields and their labels together when you can, or place them immediately next to each other so that one always follows the other in the reading order.</p> <p data-origPath="/html/body/section/section[2]/p[3]">And always clearly identify the purpose of form fields using the <code class="literal">label</code> element. You should also always add the new HTML5 <code class="literal">for</code> attribute so that the labels can be located regardless of how the reader enters the field or where they are located in the document markup. This attribute identifies the <code class="literal">id</code> of the form element the <code class="literal">label</code> element labels:</p> <pre class="screen" data-origPath="/html/body/section/section[2]/pre[1]">&lt;label id="fname-label" for="fname"&gt;First name:&lt;/label&gt; &lt;input type="text" id="fname" name="first-name" aria-labelledby="fname-label" /&gt;</pre> <p data-origPath="/html/body/section/section[2]/p[4]">I’ve also added the <code class="literal">aria-labelledby</code> attribute to the <code class="literal">input</code> element in this example to ensure maximum compatibility across systems, but its use is critical if your form field is not identified by a <code class="literal">label</code> element (only <code class="literal">label</code> takes the <code class="literal">for</code> attribute). As the <code class="literal">label</code> element can be used in just about every element that can carry a label, there’s little good reason to omit using it.</p> <p data-origPath="/html/body/section/section[2]/p[5]">For example, if you have to use a table to lay out your form, don’t be lazy and use table cells alone to convey meaning:</p> <pre class="screen" data-origPath="/html/body/section/section[2]/pre[2]">&lt;table&gt; &lt;tr&gt; &lt;td&gt; &lt;label id="fname-label" for="fname"&gt;First name:&lt;/label&gt; &lt;/td&gt; &lt;td&gt; &lt;input type="text" id="fname" name="first-name" aria-labelledby="fname-label" /&gt; &lt;/td&gt; &lt;/tr&gt;&lt;table&gt;</pre> <p data-origPath="/html/body/section/section[2]/p[6]">Note that you also should include the <code class="literal">for</code> attribute regardless of whether the <code class="literal">label</code> precedes, follows or includes the form field.</p> <p data-origPath="/html/body/section/section[2]/p[7]">Another pain point comes when a reader fills in a form only to discover after the fact that you had special instructions they were supposed to follow. When specifying entry requirements for completing the field, include them within the <code class="literal">label</code> or attach an <code class="literal">aria-describedby</code> attribute so that the reader can be informed right away:</p> <pre class="screen" data-origPath="/html/body/section/section[2]/pre[3]">&lt;label for="username-label"&gt;User name:&lt;/label&gt; &lt;input type="text" id="uname" name="username" aria-labelledby="username-label" aria-describedby="username-req" /&gt; &lt;span id="username-req"&gt;User names must be between 8 and 16 characters in length and contain only alphanumeric characters.&lt;/span&gt;</pre> </body> </html>