Accessibility
Semantic HTML
- Semantical HTML section guide.
- Semantic HTML presentation.
- Semantic search element.
Structure Accessibility
- Semantics section reference.
<header>:role="banner"<nav>:role="navigation"<main>:role="main"<aside>:role="complementary"<section>:role="region"<article>:role="article"<footer>:role="contentinfo"
<header>
<nav>
<ul>
<li><a></a></li>
</ul>
</nav>
</header>
<main>
<section></section>
</main>
<footer></footer>
Heading Accessibility
- 7 heading levels:
<div role="heading" aria-level="7"></div> - One
<h1>per page
Navigation Accessibility
- Have a HTML sitemap.
- Support keyboard navigation (Key and Tab Index).
- Breadcrumbs a11y:
aria-label="breadcrumbs"aria-label="page"
<nav aria-label="breadcrumbs">
<ol>
<li>
<a href="https://example.com/"> Home </a>
</li>
<li>
<a href="https://example.com/products"> Products </a>
</li>
<li>
<a href="https://example.com/products/childrens-clothing"> Children's clothing </a>
</li>
<li>
<a href="https://example.com/products/childrens-clothing/shoes" aria-current="page"> Shoes </a>
</li>
</ol>
</nav>
Section Accessibility
<section aria-labelledby="sectionHeader1">
<h2 id="sectionHeader1">A great section</h2>
</section>
<section aria-labelledby="sectionHeader2">
<h2 id="sectionHeader2">An even better section</h2>
</section>
Article Accessibility
The <article> element is used to represent a fully self-contained region of content
<article>
<header>
<h1>Why you should buy more cheeses than you currently do</h1>
</header>
<section>
<header>
<h2>Part 1: Variety is spicy</h2>
</header>
<!-- cheesy content -->
</section>
<section>
<header>
<h2>Part 2: Cows are great</h2>
</header>
<!-- more cheesy content -->
</section>
</article>
Reference Accessibility
<cite><q><blockquote><code>
<p>
Every time Kenny is killed, Stan will announce
<q cite="http://en.wikipedia.org/wiki/Kenny_McCormick#Cultural_impact"> Oh my God, you/they killed Kenny! </q>.
</p>
<blockquote cite="https://www.huxley.net/bnw/four.html">
<p>Words can be like X-rays, if you use them properly – they'll go through anything. You read and you're pierced.</p>
</blockquote>
<cite>– Ados Huxley, Brave New World</cite>
Link Accessibility
<article>
<h2 id="article1-title">My article</h2>
<p>Article brief description with truncation...</p>
<a href="article1-url" aria-labelledby="article1-title">Read more</a>
</article>
Text Accessibility
<b><strong><mark><ins><del><abbr>: 专有名词解释<abbr title="HyperText Markup Language">HTML</abbr>
不要将 <b> 元素与 <strong>、<em> 或 <mark> 元素混淆:
<strong>元素表示某些重要性的文本<em>强调文本<mark>元素表示某些相关性的文本
Text Color A11Y
- Devtool inspect elements A11Y for color contrast ratio.
- Don't forget
::selection.
Text Spacing A11Y
line-heightof blocks of text should be 1.5.- space between paragraphs should be 1.5 times the
line-height(so a minimum of2.25 rem). - Line height (line spacing) to at least 1.5 times the font size.
- Spacing following paragraphs to at least 2 times the font size.
- Letter spacing (tracking) to at least 0.12 times the font size.
- Word spacing to at least 0.16 times the font size.
Button Accessibility
Use <button> for clickable elements
Image Accessibility
alt=""
SVG Accessibility
<title><desc>
<svg width="100" height="75">
<title>Dark rectangle</title>
<desc>A grey rectangle with rounded corners and a dark green border</desc>
<rect width="75" height="50" rx="20" ry="20" fill="#666" stroke="#229b23" stroke-fill="1" />
</svg>
Figure Accessibility
<figure aria-labelledby="image-alt">
<img src="" alt="" />
<br />
<figcaption id="image-alt"></figcaption>
</figure>
Audio Source Accessibility
src=""type=""
Form Accessibility
Group Related Fields
With fieldset and legend:
<form role="form">
<fieldset>
<legend>Choose one of these three items:</legend>
<input id="one" type="radio" name="items" value="one" />
<label for="one">Choice One</label><br />
<input id="two" type="radio" name="items" value="two" />
<label for="two">Choice Two</label><br />
<input id="three" type="radio" name="items" value="three" />
<label for="three">Choice Three</label>
</fieldset>
</form>
Input Accessibility
label[for]input.aria-labelandaria-describedbyfor input hint.aria-invalidfor error input.aria-hiddenfor hidden input.
<form role="form">
<label for="name">Name:</label>
<input id="name" name="name" type="text" />
</form>
<form role="form">
<label for="name">Name:</label>
<span class="prefix-input">
<span class="prefix-icon" id="name-icon" aria-label="Input Prefix Icon">
<icon />
</span>
<input id="name" name="name" type="text" aria-describedby="name-icon" />
</span>
</form>
<form role="form">
<label for="email-address"> Your Email Address </label>
<span id="email-error"> Error: Your email address must contain an @ symbol </span>
<input id="email-address" name="email-address" type="email" aria-describedby="email-error" aria-invalid="true" />
</form>
export default function Field() {
return (
<>
<div className="user-code-field">
<input
id="userCode"
aria-describedby={
errors.userCode ? 'user-code-error' : 'user-code-help'
}
/>
<span id="user-code-help" className="user-code-help">
Enter your 4 digit user code
</span>
</div>
{errors.userCode && (
<div id="user-code-error" role="alert" className="error">
You must enter your 4 character user code
</div>
)}
</>
)
}
Time Accessibility
<time datetime="2016-09-15">Thursday, September 15<sup>th</sup></time>
Address Accessibility
<footer>
<section class="contact" vocab="http://schema.org/" typeof="LocalBusiness">
<h2>Contact us!</h2>
<address property="email">
<a href="mailto:us@example.com">us@example.com</a>
</address>
<address property="address" typeof="PostalAddress">
<p property="streetAddress">123 Main St., Suite 404</p>
<p>
<span property="addressLocality">Your Town</span>, <span property="addressRegion">AK</span>,
<span property="postalCode">12345</span>
</p>
<p property="addressCountry">United States of America</p>
</address>
</section>
</footer>
Color Contrast
- more than 4.5:1 ratio
Keys and Tabindex Accessibility
<a id="second" href="" accesskey="c"></a>
document.addEventListener('keyup', (event) => {
switch (event.keyCode) {
// escape
case 27:
// exit
break
// enter || space bar
case 13 || 32:
// submit or something
break
// left arrow
case 37:
// move back / previous
break
// right arrow
case 39:
// move forward
break
// up arrow
case 38:
// move up
break
// down arrow
case 40:
// move down
break
default:
throw new Error('Unsupported key!')
}
})
/**
* Traps the tab key inside of the context, so the user can't accidentally get
* stuck behind it.
*
* Note that this does not work for VoiceOver users who are navigating with
* the VoiceOver commands, only for default tab actions. We would need to
* implement something like the inert attribute for that (see https://github.com/WICG/inert)
* @param {object} e the Event object
*/
export function trapTabKey(e, context) {
if (e.key !== 'Tab')
return
const focusableItems = getFocusable(context)
const focusedItem = document.activeElement
const focusedItemIndex = focusableItems.indexOf(focusedItem)
if (e.shiftKey) {
if (focusedItemIndex === 0) {
focusableItems[focusableItems.length - 1].focus()
e.preventDefault()
}
} else {
if (focusedItemIndex === focusableItems.length - 1) {
focusableItems[0].focus()
e.preventDefault()
}
}
}
Self-Closing Tags
Self-closing tags (<tag />) do not exist in HTML.
If a trailing / (slash) character is present in the start tag of an HTML element,
HTML parsers ignore that slash character:
<div>This text is inside the div.</div>
<div />This text is inside the div.
<input />This text is outside the input.
<input>This text is outside the input.</input>
Further reading:
ARIA
Web Accessibility Initiative - Accessible Rich Internet Applications:
aria-label.aria-labelledby="dropdownMenuButton": dropdown/form>.aria-describedBy: input + small.
<label id="l1" for="f3">label text</label>
<input type="text" id="f3" aria-labelledby="l1 l2" />
<p>other content</p>
<span tabindex="-1" id="l2">more label text</span>
<div aria-describedby="test">text</div>
<div id="test" role="tooltip">tooltip text</div>
<div role="dialog" aria-label="login" aria-describedby="log1">
<div id="log1" tabindex="-1">Provide user name and password to login.</div>
</div>
aria-disabled="true": disable element.aria-hidden="true".aria-controls="navbarSupportedContent": navigation/select.aria-expanded="false": dropdown.aria-haspopup="true": dropdown/popup.aria-current="pages: breadcrumb.aria-valuenow/aria-valuemin/aria-valuemax: progress.- role.
<header>:role="banner".<nav>:role="navigation".<main>:role="main".<section>:role="region".<article>:role="article".<aside>:role="complementary".<footer>:role="contentinfo".<form>:role="form".- 7th heading level:
<div role="heading" aria-level="7"></div>. role="button".role="checkbox".role="gridcell".role="link".role="menuitem".role="menuitemcheckbox".role="menuitemradio".role="option".role="progressbar".role="radio".role="scrollbar".role="searchbox".role="separator (when focusable)".role="slider".role="spinbutton".role="switch".role="tab".role="tabpanel".role="textbox".role="tooltip".role="treeitem".role="presentation": removes the semantics of an element. If set an interactive or focusable element torole="presentation", assistive technology user will not know what it is or how to use it.role="application".
<button class="list-expander" aria-expanded="false" aria-controls="expandable-list-1">Expand List</button>
<ul id="expandable-list-1">
<li><a href="http://example.com">Sample Link</a></li>
<li><a href="http://example.com">Sample Link 2</a></li>
<li><a href="http://example.com">Sample Link 3</a></li>
</ul>
const listExpander = document.querySelector('.list-expander')
const list = document.querySelector('#expandable-list-1')
listExpander.addEventListener('click', (e) => {
if (list.getAttribute('aria-expanded') === 'true')
list.setAttribute('aria-expanded', 'false')
else
list.setAttribute('aria-expanded', 'true')
})
Dialog ARIA Role
<div id="dialog_layer" class="dialogs">
<div
id="dialog1"
role="dialog"
aria-labelledby="dialog1_label"
aria-describedby="dialog1_desc"
aria-modal="true"
class="hidden"
>
<h2 id="dialog1_label" class="dialog_label">Address Added</h2>
<p id="dialog1_desc" class="dialog_desc">
The address you provided has been added to your list of delivery addresses. It is ready for immediate use. If you
wish to remove it, you can do so from
<a href="#" onclick="openDialog('dialog2', this)"> your profile. </a>
</p>
<div class="dialog_form_actions">
<button type="button" id="dialog1_close_btn" onclick="closeDialog(this)">OK</button>
</div>
</div>
<div
id="dialog2"
role="dialog"
aria-labelledby="dialog2_label"
aria-describedby="dialog2_desc"
aria-modal="true"
class="hidden"
>
<h2 id="dialog2_label" class="dialog_label">End of the Road!</h2>
<p id="dialog2_desc" class="dialog_desc">
You activated a fake link or button that goes nowhere! The link or button is present for demonstration purposes
only.
</p>
<div class="dialog_form_actions">
<button type="button" id="dialog2_close_btn" onclick="closeDialog(this)">Close</button>
</div>
</div>
</div>
HTML First over ARIA
<!--div role="banner"-->
<header></header>
<!--div role="navigation"-->
<nav></nav>
<!--div role="main"-->
<main></main>
<!--div role="region"-->
<section [accessible name]></section>
<!--div role="complementary"-->
<aside></aside>
<!--div role="contentinfo"-->
<footer></footer>
<!--div role="form"-->
<form></form>
<div role="search"></div>
Accessibility Best Practices
A11y audit list:
- Keyboard-only navigation.
- Voice control.
- Screen reader.
- High contrast mode.
- Dark mode.
- Browser zoom.
- Don't use
aria-hiddenon the<body>element. - Complete meta header:
- Add missing languages.
- Make sure
documenthas atitleelement. - Tool:
react-helmet.
- Fix low text contrast: 确保文本与其背景保持足够的对比.
- 不要将颜色作为传达信息的唯一手段 (色盲/弱).
- Add missing alternative text.
- Remove empty links and buttons.
- 注意表单:
- Add missing labels.
- 提供输入焦点的视觉提示.
- 避免组件识别障碍.
- Make sure
IDsandKeysof elements are unique. - Required context role.
- Required aria attribute.
- Valid aria attribute.
Accessibility Checklist
- W3C ARIA Usage Rule
- WebAIM WCAG (Web Content Accessibility Guidelines) 2 Checklist
- A11Y Project
- A11Y 101
Accessibility Tools
Accessibility References
WAI-ARIA: improve website’s accessibility withWAI-ARIA.ARIA: W3C official examples.WebAIM: Million project.- A11y community: learn about a11y.
- Cognitive a11y resources.
- A11y for PDF.
- A11y for design system.
- Assistive technology for readers.