Web accessibility - It’s not just about HTML

A presentation at ffconf in November 2023 in Brighton, UK by Ire Aderinokun

Slide 1

Slide 1

Web Accessibility: it’s not just about HTML Ire Aderinokun @ ffconf 2023 @ireaderinokun / @ire@front-end.social

Slide 2

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

Slide 3

Web accessibility is the inclusive practice of ensuring there are no barriers that prevent access to websites

Slide 4

Slide 4

Physical disabilities

Slide 5

Slide 5

Situational disabilities

Slide 6

Slide 6

Socio-economic restrictions

Slide 7

Slide 7

Accessibility is about inclusion

Slide 8

Slide 8

Slide 9

Slide 9

  1. Content must be perceivable 🧏 2. Interface must be operable 🛠 3. Content must be understandable 📖 4. Code must be robust ⚙

Slide 10

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

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

Slide 12

https://ireade.github.io/motherduckingwebsite/

Slide 13

Slide 13

HTML can be inaccessible

Slide 14

Slide 14

Missing text alternatives ☹ <img src=“link/to/really-important-image.png”

Slide 15

Slide 15

Using the wrong elements ☹ <span>Enter your username:</span> <input type=“text”>

Slide 16

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 17

HTML

Slide 18

Slide 18

JavaScript CSS

Slide 19

Slide 19

Adding content with CSS ☹

<div id=“important”></div> #important after { content: “Really important information that everyone should know” : : }

Slide 20

Slide 20

Altering element behaviour with JavaScript ☹

<div onClick=“goToPage(‘/about’)”> About Us </div>

Slide 21

Slide 21

90% of accessibility is about using HTML correctly. The other 10% is about not using CSS/JS incorrectly.

Slide 22

Slide 22

CSS, JavaScript, & Accessibility

Slide 23

Slide 23

Part One CSS & Accessibility

Slide 24

Slide 24

CSS is used to describe the presentation of an HTML document

Slide 25

Slide 25

Slide 26

Slide 26

Slide 27

Slide 27

Slide 28

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

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

Slide 30

DOM + CSSOM - Non-visible elements = Render tree

Slide 31

Slide 31

Slide 32

Slide 32

Slide 33

Slide 33

Slide 34

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 35

Slide 36

Slide 36

Slide 37

Slide 37

#1 Don’t use CSS to convey meaning or content

Slide 38

Slide 38

<input class=“error” > <input class=“success” > .error { border-color: red; } .success { border-color: green; }

Slide 39

Slide 39

h1 after { content: “My Page Title” : : }

Slide 40

Slide 40

https://tink.uk/accessibility-support-for-css-generated-content/

Slide 41

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

Slide 42

#2 Don’t use CSS to change the semantics of HTML

Slide 43

Slide 43

Slide 44

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

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

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

Slide 47

https://frend.co/components/tooltip/

Slide 48

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

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

Slide 50

<div>Element #1</div> <div style=“visibility:hidden;”> Element #2 </div> <div>Element #3</div>

Slide 51

Slide 51

Slide 52

Slide 52

Don’t use visibility: hidden;

Slide 53

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

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

Slide 55

Source Order Visual Order

Slide 56

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

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

Slide 58

#3 Don’t write CSS that undoes the default accessible styles

Slide 59

Slide 59

Browser CSS

Slide 60

Slide 60

✅ Text & element sizes ✅ Colours & contrast ✅ Hover, focus, & active states

Slide 61

Slide 61

My CSS Browser CSS

Slide 62

Slide 62

button { font-size: 6px; }

Slide 63

Slide 63

button { color: lightgray; }

Slide 64

Slide 64

https://uxplanet.org/active-hover-and-focus-states-for-designers-d789531fe767

Slide 65

Slide 65

https://bitsofco.de/when-do-the-hover-focus-and-active-pseudo-classes-apply/

Slide 66

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 67

Slide 68

Slide 68

❌ ✅ :focus { :focus { outline: none; outline: none; other focus styles } / * * / }

Slide 69

Slide 69

button:focus:not(:focus-visible) { outline: none; } button:focus-visible { background-color: darksalmon; }

Slide 70

Slide 70

Write custom CSS cautiously

Slide 71

Slide 71

Slide 72

Slide 72

#4 Do use CSS to improve on the default accessible styles

Slide 73

Slide 73

Guideline 1.4.8 — Visual presentation

  1. 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

Slide 74

The default browser styling doesn’t meet these requirements

Slide 75

Slide 75

p { line-height: 1.5; padding: 2.25rem; max-width: 80ch; }

Slide 76

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 77

Slide 78

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

Slide 79

#5 Do adapt CSS to device capabilities

Slide 80

Slide 80

CSS

Slide 81

Slide 81

.element { color: #000; color: var(—text-color); }

Slide 82

Slide 82

.element { color: #000; color: var(—text-color); }

Slide 83

Slide 83

.element { color: #000; color: var(—text-color); }

Slide 84

Slide 84

@supports ( declaration ) { Feature-based CSS here / * * / }

Slide 85

Slide 85

Legacy code Modern code @supports (display: grid) { main { main { display: grid; display: table; } } more layout code / * * / }

Slide 86

Slide 86

Legacy code Modern code @supports (display: grid) { main { main { display: grid; display: table; } } more layout code / * * / }

Slide 87

Slide 87

#6 Do adapt CSS to user preferences

Slide 88

Slide 88

https://dbaron.org/css/user/

Slide 89

Slide 89

https://codereview.chromium.org/64843004

Slide 90

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

Slide 91

@media ( prefers-* ) { Preference-based CSS here / * * / }

Slide 92

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 93

Slide 94

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 95

Giving users control

Slide 96

Slide 96

CSS & Accessibility 1. Don’t use CSS to convey meaning or content

  1. Do use CSS to improve on the default accessible styles
  2. Don’t use CSS to change the semantics of HTML
  3. Do adapt CSS to device capabilities
  4. Don’t write CSS that undoes the default
  5. Do adapt CSS to user preferences accessible styles

Slide 97

Slide 97

Part Two JavaScript & Accessibility

Slide 98

Slide 98

JavaScript is used to make web pages more interactive

Slide 99

Slide 99

JavaScript is used to make web pages more interactive

Slide 100

Slide 100

<a> <details> <form> <summary> <input> <dialog> <select> <textarea> <option> <progress>

Slide 101

Slide 101

Slide 102

Slide 102

#1 Don’t use JavaScript for functionality HTML provides

Slide 103

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

Slide 104

<button> Do something </button>

Slide 105

Slide 105

<div> Do something </div>

Slide 106

Slide 106

Extra work 😓 <div tabindex=“0” role=“button” onKeyPress=“handleBtnKeyPress(e)” onClick=“doSomething(e)”> Do something </div>

Slide 107

Slide 107

Extra work 😓 <div tabindex=“0” role=“button” onKeyPress=“handleBtnKeyPress(e)” onClick=“doSomething(e)”> Do something </div>

Slide 108

Slide 108

Extra work 😓 <div tabindex=“0” role=“button” onKeyPress=“handleBtnKeyPress(e)” onClick=“doSomething(e)”> Do something </div>

Slide 109

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

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 111

Slide 112

Slide 112

✅ ❌ <button onClick=“goToPage(‘/about’)”> <a href=“/about”>About Us</a> About Us </button>

Slide 113

Slide 113

<button onClick=“goToPage(‘/about’)”> About Us </button> function goToPage(url) { // Do some other things window.location.href = url; }

Slide 114

Slide 114

Keep JavaScript enhancements unobtrusive

Slide 115

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

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

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

Slide 118

event.preventDefault() is the 🔑

Slide 119

Slide 119

#2 Where possible, don’t require JavaScript for critical features

Slide 120

Slide 120

Slide 121

Slide 121

Without JS With JS

Slide 122

Slide 122

Without JS With JS

Slide 123

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

Slide 124

Different groups have different access needs

Slide 125

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

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

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 128

Slide 129

Slide 129

JavaScript-disabled experience JavaScript-enabled experience

Slide 130

Slide 130

JavaScript-enabled experience JavaScript-disabled experience

Slide 131

Slide 131

JavaScript-disabled experience JavaScript-enabled experience

Slide 132

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

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

Slide 134

#3 Do use JavaScript to improve on the default accessible behaviour

Slide 135

Slide 135

Guideline 3.3 — Help users avoid and correct mistakes ✅

Slide 136

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 137

Slide 138

Slide 138

Some HTML elements aren’t accessible enough, yet ☹

Slide 139

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

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

Slide 141

https://www.digitala11y.com/accessible-jquery-html5-media-players/

Slide 142

Slide 142

Sometimes, we need JavaScript

Slide 143

Slide 143

#4 Do use JavaScript to create components that don’t exist

Slide 144

Slide 144

Slide 145

Slide 145

<tooltip> <dropdown> <carousel> <tab-group> <toggle> <card> <social-button> <accordion> <loading> <tab>

Slide 146

Slide 146

https://www.w3.org/TR/2021/NOTE-wai-aria-practices-1.2-20211129/examples/carousel/carousel-1-prev-next.html

Slide 147

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

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

Slide 149

<ul id=”slides”> <li> Slide One </li> <li> Slide Two </li> <li> Slide Three / * / / * * * * * / / / </ul> </li>

Slide 150

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

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

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

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

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

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

Slide 156

Write custom components cautiously

Slide 157

Slide 157

https://www.w3.org/TR/2021/NOTE-wai-aria-practices-1.2-20211129/examples/

Slide 158

Slide 158

https://frend.co/

Slide 159

Slide 159

https://inclusive-components.design/

Slide 160

Slide 160

JavaScript & Accessibility 1. Don’t use JavaScript for functionality HTML provides 2. Where possible, don’t require JavaScript for critical features

  1. Do use JavaScript to improve on the default accessible behaviour 2. Do use JavaScript to create components that don’t exist

Slide 161

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

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

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