theme | author | position | position2 | profilePicture | ||
---|---|---|---|---|---|---|
./ |
Ania Karoń |
Web Accessibility Specialist |
and Senior Frontend Developer |
anna-karon-photo.jpg |
Workshops
Repo: https://github.com/SnowdogApps/a11y-space
Website: A11y space
HTML, Tailwindcss, JS/TS
Deployment: Vercel (SSG)
- code review
- ANDI
- Screen readers - VoiceOver (macOS), Narrator or NDVA (Windows), ChromeVox (browser extension)
- HTML Doc - RWD, lang, title
- Landmarks:
header
,main
,footer
,section
,nav
,aside
- Semantic HTML:
<p>
,<ul><li>...</li></ul>
,<button>
,<a href="/">
,<article>
,<address>
,<time>
etc... - Headings -
<h1>
-<h6>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Page title</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<header>
...
</header>
<main>
<h1>Heading</h1>
...
</main>
<aside>
...
</aside>
<footer>
...
</footer>
</body>
</html>
Informative images convey a simple concept or information that can be expressed in a short phrase or sentence. The text alternative should convey the meaning or content that is displayed visually, which typically isn’t a literal description of the image.
labeling information, supplementing information, conveying an impression or emotion
<img src="informative-image" alt="alternative text" />
Functional images are used to initiate actions rather than to convey information, ex. in buttons and links
<a href="/">
<img src="logo-image" alt="Company logo" />
</a>
<a href="/" aria-label="Homepage">
<img src="logo-image" alt="Company logo" />
</a>
Decorative images don’t add information to the content of a page.
<img src="decorative-image" alt="" aria-hidden="true" />
An alt Decision Tree on WAI Tutorials
All graphic interactive elements without visible label, should have alternative text
::left::
Add directly on element
<button type="button" aria-label="Add to cart">
<svg>Add to cart icon</svg>
</button>
::right::
Bind element which serves as a label (ex. heading), using its id
<section type="button" aria-labelledby="section-heading">
<h2 id="section-heading">Heading section</h2>
</section>
For adding additional description (ex. form field, button),Bind element which serves as a description (ex. heading), using its id
<form>
<label for="fname">First name</label>
<input aria-describedby="int2" autocomplete="given-name" id="fname" type="text">
<p id="int2">Your first name is sometimes called your "given name".</p>
</form>
Pozor! Hide with care and caution. Don't hide crucial elements, like headings, SEO doesn't like it.
::left::
For everyone
.element {
display: none;
visibility: hidden;
}
For assistive technologies
aria-hidden="true"
<span class="aria-hidden">Decorative element</span>
::right::
Only visually
/* Hiding class, making content visible only to screen readers but not visually */
/* "sr" meaning "screen-reader" */
.sr-only:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
Tailwindcss - sr-only
focus
state should be well visible
- css
outline
, browser providefocus
state by default, if you don't style focus state, don't removeoutline: none
- order focusable elements, focus management
:focus
i:focus-visible
<style> li { font-size: 0.875rem; } </style>
::left::
Aria - roles and attributes
- role=tablist
- role=tab
- role=tabpanel
- aria-selected
- aria-labelledby
- aria-controls
Keyboard navigation
Tab
- focus active tabLeft arrow
,Right arrow
- move focus between tabsSpace
iEnter
- activate tabHome
(optional) - move focus to the first tabEnd
(optional) - move focus to the last tab
::right::
<div>
<h2 id="heading">Heading</h2>
<div role="tablist" aria-labelledby="heading">
<button id="tab-1" type="button" role="tab" aria-selected="true" aria-controls="tabpanel-1">
<span>Tab 1</span>
</button>
<button id="tab-2" type="button" role="tab" aria-selected="false" aria-controls="tabpanel-2" tabindex="-1">
<span>Tab 1</span>
</button>
</div>
<div id="tabpanel-1" role="tabpanel" aria-labelledby="tab-1">
<p>
Content tab 1
</p>
</div>
<div id="tabpanel-2" role="tabpanel" aria-labelledby="tab-3" aria-hidden="true">
<p>
Content tab 2
</p>
</div>
</div>
<style> li { font-size: 0.875rem; } </style>
::left::
Aria - roles and attributes
- role=dialog
- aria-modal
- aria-labelledby
- aria-hidden
- aria-haspopup (trigger)
- aria-expanded (trigger)
Keyboard navigation
Tab
- focus next focusable element inside a dialogsShift + Tab
- focus previous focusable element inside a dialogsEscape
- close dialog and move focus back to the page (on trigger if exist)
::right::
<div
role="dialog"
aria-modal="true"
aria-hidden="true"
class="dialog"
aria-labelledby="heading"
>
<div class="dialog-content" autofocus tabindex="0">
<h2 id="heading">Heading</h2>
dialog content
<button type="button">Close</button>
</div>
</div>
aria-live
- announces dynamically changed content (set on container)polite
value - informs about changes when AT finish current taskassertive
value - informs about changes immediatelyaria-atomic
- informs about how elements inside live region (container witharia-live
attr) should be annoounced - only changes:false
value, all:true
value
layout: thankyou