Slide 1
Web Accessibility:
it’s not just about HTML Ire Aderinokun @ ffconf 2023 @ireaderinokun / @ire@front-end.social
Slide 2
“By default, HTML is accessible. Web accessibility involves ensuring that content remains accessible.” https://developer.mozilla.org/en-US/docs/Learn/Accessibility
Slide 3
Web accessibility is the inclusive practice of ensuring there are no barriers that prevent access to websites
Slide 4
Slide 5
Slide 6
Socio-economic restrictions
Slide 7
Accessibility is about inclusion
Slide 8
Slide 9
- Content must be perceivable 🧏 2. Interface must be operable 🛠 3. Content must be understandable 📖 4. Code must be robust ⚙
Slide 10
“By default, HTML is accessible. Web accessibility involves ensuring that content remains accessible.” https://developer.mozilla.org/en-US/docs/Learn/Accessibility
Slide 11
“By default, HTML is accessible, if used correctly. Web accessibility involves ensuring that content remains accessible.” https://developer.mozilla.org/en-US/docs/Learn/Accessibility
Slide 12
https://ireade.github.io/motherduckingwebsite/
Slide 13
Slide 14
Missing text alternatives ☹
<img src=“link/to/really-important-image.png”
Slide 15
Using the wrong elements ☹
<span>Enter your username:</span> <input type=“text”>
Slide 16
Weird tab order ☹
<ul> <li><a href=“/one” tabindex=“2”>Link One</a></li> <li><a href=“/two” tabindex=“3”>Link Two</a></li> <li><a href=“/three” tabindex=“1”>Link Three</a></li> </ul>
Slide 17
Slide 18
Slide 19
Adding content with CSS ☹
<div id=“important”></div>
#important
after {
content: “Really important information that everyone should know”
:
:
}
Slide 20
Altering element behaviour with JavaScript ☹
<div onClick=“goToPage(‘/about’)”> About Us </div>
Slide 21
90% of accessibility is about using HTML correctly. The other 10% is about not using CSS/JS incorrectly.
Slide 22
CSS, JavaScript, & Accessibility
Slide 23
Part One
CSS & Accessibility
Slide 24
CSS is used to describe the presentation of an HTML document
Slide 25
Slide 26
Slide 27
Slide 28
DOM <head> <title>Understanding the Critical Rendering Path</title> <link rel=”stylesheet” href=”style.css”> </head> <body> <header> <h1>Understanding the Critical Rendering Path</h1> </header> <main> <h2>Introduction</h2> <p>Lorem ipsum dolor sit amet</p> </main> <footer><small>Copyright 2017</small></footer> </body>
Slide 29
CSSOM body { font-size: 18px; }
header { color: plum; } h1 { font-size: 28px; }
main { color: firebrick; } h2 { font-size: 20px; }
footer { display: none; }
Slide 30
DOM + CSSOM - Non-visible elements = Render tree
Slide 31
Slide 32
Slide 33
Slide 34
AOM <form> <p>Make a choice:</p> <input type=“radio” name=“choice” id=“yes” /> <label>Yes</label> <input type=“radio” name=“choice” id=“no” /> <label>No</label>
<input type=“checkbox” name=“agree” id=“agree” /> <label>I agree</label> </form>
Slide 35
Slide 36
Slide 37
#1
Don’t use CSS to convey meaning or content
Slide 38
<input class=“error” > <input class=“success” >
.error { border-color: red; } .success { border-color: green; }
Slide 39
h1
after { content: “My Page Title”
:
:
}
Slide 40
https://tink.uk/accessibility-support-for-css-generated-content/
Slide 41
“In other words, use CSS generated content to change or supplement the design, but not to create or alter important content on the page.”
— Léonie Watson https://tink.uk/accessibility-support-for-css-generated-content/
Slide 42
#2
Don’t use CSS to change the semantics of HTML
Slide 43
Slide 44
display: none;
visibility: hidden;
opacity: 0;
position: absolute; top: -9999px; left: -9999px;
Visually hidden?
✅
✅
✅
✅
Box model generated?
❌
✅
✅
✅
Affects layout?
❌
✅
✅
❌
Read by assistive technologies?
❌
❌
✅
✅
Slide 45
display: none;
visibility: hidden;
opacity: 0;
position: absolute; top: -9999px; left: -9999px;
Visually hidden?
✅
✅
✅
✅
Box model generated?
❌
✅
✅
✅
Affects layout?
❌
✅
✅
❌
Read by assistive technologies?
❌
❌
✅
✅
Slide 46
display: none;
visibility: hidden;
opacity: 0;
position: absolute; top: -9999px; left: -9999px;
Visually hidden?
✅
✅
✅
✅
Box model generated?
❌
✅
✅
✅
Affects layout?
❌
✅
✅
❌
Read by assistive technologies?
❌
❌
✅
✅
Slide 47
https://frend.co/components/tooltip/
Slide 48
display: none;
visibility: hidden;
opacity: 0;
position: absolute; top: -9999px; left: -9999px;
Visually hidden?
✅
✅
✅
✅
Box model generated?
❌
✅
✅
✅
Affects layout?
❌
✅
✅
❌
Read by assistive technologies?
❌
❌
✅
✅
Slide 49
display: none;
visibility: hidden;
opacity: 0;
position: absolute; top: -9999px; left: -9999px;
Visually hidden?
✅
✅
✅
✅
Box model generated?
❌
✅
✅
✅
Affects layout?
❌
✅
✅
❌
Read by assistive technologies?
❌
❌
✅
✅
Slide 50
<div>Element #1</div>
<div style=“visibility:hidden;”> Element #2 </div>
<div>Element #3</div>
Slide 51
Slide 52
Don’t use visibility: hidden;
Slide 53
display: none;
visibility: hidden;
opacity: 0;
position: absolute; top: -9999px; left: -9999px;
Visually hidden?
✅
✅
✅
✅
Box model generated?
❌
✅
✅
✅
Affects layout?
❌
✅
✅
❌
Read by assistive technologies?
❌
❌
✅
✅
Slide 54
display: none;
visibility: hidden;
opacity: 0;
position: absolute; top: -9999px; left: -9999px;
Visually hidden?
✅
✅
✅
✅
Box model generated?
❌
✅
✅
✅
Affects layout?
❌
✅
✅
❌
Read by assistive technologies?
❌
❌
✅
✅
Slide 55
Source Order
Visual Order
Slide 56
Source order
Visual order
<body> body { display: flex } <footer>…</footer> header { order: 1 } <nav>…</nav> nav { order: 2 } <header>…</header> main { order: 3 } <main>…</main> footer { order: 4 } </body>
Slide 57
“With this power comes great responsibility”
— Rachel Andrew https://rachelandrew.co.uk/archives/2015/07/28/modern-css-layout-power-and-responsibility/
Slide 58
#3
Don’t write CSS that undoes the default accessible styles
Slide 59
Slide 60
✅ Text & element sizes ✅ Colours & contrast ✅ Hover, focus, & active states
Slide 61
Slide 62
button { font-size: 6px; }
Slide 63
button { color: lightgray; }
Slide 64
https://uxplanet.org/active-hover-and-focus-states-for-designers-d789531fe767
Slide 65
https://bitsofco.de/when-do-the-hover-focus-and-active-pseudo-classes-apply/
Slide 66
:active then :focus then :hover ❌
:hover then :focus then :active ✅
button:active { background-color: green; }
button:hover { background-color: red; }
button:focus { background-color: blue; }
button:focus { background-color: blue; }
button:hover { background-color: red; }
button:active { background-color: green; }
Slide 67
Slide 68
❌
✅
:focus { :focus { outline: none; outline: none; other focus styles }
/
*
*
/
}
Slide 69
button:focus:not(:focus-visible) { outline: none; }
button:focus-visible { background-color: darksalmon; }
Slide 70
Write custom CSS cautiously
Slide 71
Slide 72
#4
Do use CSS to improve on the default accessible styles
Slide 73
Guideline 1.4.8 — Visual presentation
- Text blocks should be no wider than 80 characters, for maximum readability. 2. Line height should be at least 1.5 times the text size within paragraphs, and at least 2.25 times the text size between paragraphs.
Slide 74
The default browser styling doesn’t meet these requirements
Slide 75
p { line-height: 1.5; padding: 2.25rem; max-width: 80ch; }
Slide 76
Guideline 2.4.1 — Bypass blocks
A mechanism should be provided that allows the user to skip straight to the main content or functionality available on the page, past the repeated features (such as the company logo or navigation).
Slide 77
Slide 78
Guideline 2.4.1 — Bypass blocks A mechanism should be provided that allows the user to skip straight to the main content or functionality available on the page, past the repeated features (such as the company logo or navigation). … If a proper structure of headings and semantic containers is provided to navigate with (for example <section>, <aside>, etc.), then an added “skip link” is not needed.
Slide 79
#5
Do adapt CSS to device capabilities
Slide 80
Slide 81
.element { color: #000; color: var(—text-color); }
Slide 82
.element { color: #000; color: var(—text-color); }
Slide 83
.element { color: #000; color: var(—text-color); }
Slide 84
@supports ( declaration ) { Feature-based CSS here
/
*
*
/
}
Slide 85
Legacy code
Modern code @supports (display: grid) { main {
main { display: grid; display: table; } } more layout code
/
*
*
/
}
Slide 86
Legacy code
Modern code @supports (display: grid) { main {
main { display: grid; display: table; } } more layout code
/
*
*
/
}
Slide 87
#6
Do adapt CSS to user preferences
Slide 88
https://dbaron.org/css/user/
Slide 89
https://codereview.chromium.org/64843004
Slide 90
“All users, including users with disabilities, [should] have equal control over the environment they use to access the web” https://www.w3.org/TR/UAAG20
Slide 91
@media ( prefers-* ) { Preference-based CSS here
/
*
*
/
}
Slide 92
Adapt to motion preferences
.element { animation: bouncing 1.5s linear infinite alternate; }
@media ( prefers-reduced-motion: reduce ) { .element { animation: fade 0.5s ease-in both; } }
https://www.smashingmagazine.com/2020/09/design-reduced-motion-sensitivities/
Slide 93
Slide 94
Adapt to motion preferences
prefers-reduced-motion
Adapt to data preferences
prefers-reduced-data
Adapt to colour preferences
prefers-color-scheme
Adapt to contrast preferences
prefers-contrast
Adapt to trasparency preferences
prefers-reduced-transparency
Slide 95
Slide 96
CSS & Accessibility 1. Don’t use CSS to convey meaning or content
- Do use CSS to improve on the default accessible styles
- Don’t use CSS to change the semantics of HTML
- Do adapt CSS to device capabilities
- Don’t write CSS that undoes the default
- Do adapt CSS to user preferences
accessible styles
Slide 97
Part Two
JavaScript & Accessibility
Slide 98
JavaScript is used to make web pages more interactive
Slide 99
JavaScript is used to make web pages more interactive
Slide 100
<a>
<details> <form> <summary>
<input>
<dialog> <select> <textarea>
<option> <progress>
Slide 101
Slide 102
#1
Don’t use JavaScript for functionality HTML provides
Slide 103
✅ Triggered by mouse, enter key, and space bar ✅ Focusable via the keyboard and other input devices ✅ Accessible name and state provided to assistive tech
Slide 104
<button> Do something </button>
Slide 105
<div> Do something </div>
Slide 106
Extra work 😓 <div tabindex=“0” role=“button” onKeyPress=“handleBtnKeyPress(e)” onClick=“doSomething(e)”> Do something </div>
Slide 107
Extra work 😓 <div tabindex=“0” role=“button” onKeyPress=“handleBtnKeyPress(e)” onClick=“doSomething(e)”> Do something </div>
Slide 108
Extra work 😓 <div tabindex=“0” role=“button” onKeyPress=“handleBtnKeyPress(e)” onClick=“doSomething(e)”> Do something </div>
Slide 109
More extra work 😰 <div tabindex=“0”
function handleBtnKeyPress(e) {
role=“button”
if ( e.keyCode
32 ||
e.keyCode
13) {
onKeyPress=“handleBtnKeyPress(e)” onClick=“doSomething(e)”>
doSomething(e);
Do something
}
</div>
=
=
=
=
=
=
}
Slide 110
Even more extra work 🥵 <div tabindex=“0” role=“button” onKeyPress=“handleBtnKeyPress(e)” onClick=“doSomething(e)” aria-pressed=”false”> Toggle </div>
Slide 111
Slide 112
✅
❌
<button onClick=“goToPage(‘/about’)”> <a href=“/about”>About Us</a>
About Us </button>
Slide 113
<button onClick=“goToPage(‘/about’)”> About Us </button>
function goToPage(url) { // Do some other things window.location.href = url; }
Slide 114
Keep JavaScript enhancements unobtrusive
Slide 115
<a href=“/about” onClick=“goToPage(e, ’/about’)”> About Us </a>
function goToPage(e, url) { e.preventDefault(); // Do some other things window.location.href = url; }
Slide 116
<a href=“/about” onClick=“goToPage(event, ’/about’)”> About Us </a>
function goToPage(event, url) { event.preventDefault(); // Do some other things window.location.href = url; }
Slide 117
<a href=“/about” onClick=“goToPage(e, ’/about’)”> About Us </a>
function goToPage(e, url) { e.preventDefault(); // Do some other things window.location.href = url; }
Slide 118
event.preventDefault() is the 🔑
Slide 119
#2
Where possible, don’t require JavaScript for critical features
Slide 120
Slide 121
Slide 122
Slide 123
“While WCAG 1.0 from 1999 required that pages be functional and accessible with scripting disabled, WCAG 2 and all other modern guidelines allow you to require JavaScript” https://webaim.org/techniques/javascript/
Slide 124
Different groups have different access needs
Slide 125
People with physical disabilities are more likely to rely on JS Only 0.07% of screen reader users have JavaScript disabled. The global average is 1%.
Slide 126
People with socio-economic restrictions are more likely to avoid JS Over 50% of the Sudanese mobile browsing is with Opera Mini
Slide 127
Average File Sizes 430 KB
27 KB HTML
66 KB CSS
https://almanac.httparchive.org/en/2021/page-weight
JS
Slide 128
Slide 129
JavaScript-disabled experience
JavaScript-enabled experience
Slide 130
JavaScript-enabled experience JavaScript-disabled experience
Slide 131
JavaScript-disabled experience
JavaScript-enabled experience
Slide 132
“Just because JavaScript is used on a page does not mean that the page is inaccessible. In many cases, JavaScript can be used to greatly improve accessibility and optimize the user experience.” https://webaim.org/techniques/javascript/
Slide 133
“Just because JavaScript is used on a page does not mean that the page is inaccessible. In many cases, JavaScript can be used to greatly improve accessibility and optimize the user experience.” https://webaim.org/techniques/javascript/
Slide 134
#3
Do use JavaScript to improve on the default accessible behaviour
Slide 135
Guideline 3.3 — Help users avoid and correct mistakes ✅
Slide 136
Guideline 3.3.3 — When an error is detected and suggestions for correction are known, provide these to the user
Slide 137
Slide 138
Some HTML elements aren’t accessible enough, yet ☹
Slide 139
Problems with <video> ❌ Controls not focusable via keyboard ❌ Can’t pause/play video using space key ❌ No arrow key support for scrubber & more
Slide 140
“Modern browsers provide a default media player. Most have limited functionality to support accessibility.” https://www.w3.org/WAI/media/av/player/
Slide 141
https://www.digitala11y.com/accessible-jquery-html5-media-players/
Slide 142
Sometimes, we need JavaScript
Slide 143
#4
Do use JavaScript to create components that don’t exist
Slide 144
Slide 145
<tooltip>
<dropdown>
<carousel> <tab-group> <toggle> <card> <social-button>
<accordion> <loading>
<tab>
Slide 146
https://www.w3.org/TR/2021/NOTE-wai-aria-practices-1.2-20211129/examples/carousel/carousel-1-prev-next.html
Slide 147
Guidelines related to carousels 1.3.1 — Information, structure, and relationships conveyed through presentation can be programmatically determined 2.1.1 — All functionality should be accessible using keyboard controls 2.2.2 — Controls should be provided to pause, stop, or hide moving content 4.1.2 — The name and role of user interface components (e.g. form inputs, buttons, links, etc.) should be programmatically determinable
Slide 148
Guidelines related to carousels 1.3.1 — Information, structure, and relationships conveyed through presentation can be programmatically determined 2.1.1 — All functionality should be accessible using keyboard controls 2.2.2 — Controls should be provided to pause, stop, or hide moving content 4.1.2 — The name and role of user interface components (e.g. form inputs, buttons, links, etc.) should be programmatically determinable
Slide 149
<ul id=”slides”> <li>
Slide One
</li>
<li>
Slide Two
</li>
<li>
Slide Three
/
*
/
/
*
*
*
*
*
/
/
/
</ul>
</li>
Slide 150
Guidelines related to carousels 1.3.1 — Information, structure, and relationships conveyed through presentation can be programmatically determined 2.1.1 — All functionality should be accessible using keyboard controls 2.2.2 — Controls should be provided to pause, stop, or hide moving content 4.1.2 — The name and role of user interface components (e.g. form inputs, buttons, links, etc.) should be programmatically determinable
Slide 151
<section> <div> <button>Toggle Play Slideshow</button> <button>Previous Slide</button> <button>Next Slide</button> </div> <ul id=”slides”> <li> … </li> </ul> </section>
Slide 152
<section> <div> <button>Toggle Play Slideshow</button> <button>Previous Slide</button> <button>Next Slide</button> </div> <ul id=”slides”> <li> … </li> </ul> </section>
Slide 153
<section> <div> <button>Toggle Play Slideshow</button> <button>Previous Slide</button> <button>Next Slide</button> </div> <ul id=”slides”> <li> … </li> </ul> </section>
Slide 154
Guidelines related to carousels 1.3.1 — Information, structure, and relationships conveyed through presentation can be programmatically determined 2.1.1 — All functionality should be accessible using keyboard controls 2.2.2 — Controls should be provided to pause, stop, or hide moving content 4.1.2 — The name and role of user interface components (e.g. form inputs, buttons, links, etc.) should be programmatically determinable
Slide 155
<section aria-roledescription=”carousel” aria-label=“Slideshow”> <div> <button>Toggle Play Slideshow</button> <button aria-controls=”slides”>Previous Slide</button> <button aria-controls=”slides”>Next Slide</button> </div> <ul id=”slides”> <li role=”group” aria-roledescription=”slide” aria-label=”1 of 3”> … </li> </ul> </section>
Slide 156
Write custom components cautiously
Slide 157
https://www.w3.org/TR/2021/NOTE-wai-aria-practices-1.2-20211129/examples/
Slide 158
Slide 159
https://inclusive-components.design/
Slide 160
JavaScript & Accessibility 1. Don’t use JavaScript for functionality HTML provides 2. Where possible, don’t require JavaScript for critical features
- Do use JavaScript to improve on the default accessible behaviour 2. Do use JavaScript to create components that don’t exist
Slide 161
“By default, HTML is accessible, if used correctly. Web accessibility involves ensuring that content remains accessible.” https://developer.mozilla.org/en-US/docs/Learn/Accessibility
Slide 162
“So next time someone tells you to make things accessible, tell them that instead you don’t intend to make it inaccessible in the rst place.”
— George Kemp
fi
https://dev.to/gkemp94/the-web-is-accessible-by-default-stop-breaking-it-4cg4
Slide 163
Thank you! Ire Aderinokun 🇳🇬 🇬🇧 Independent User Interface Engineer Google Web Expert Co-Founder Helicarrier
ireaderinokun.com bitsofco.de @ireaderinokun / @ire@front-end.social / @ire.bsky.social