A place to cache linked articles (think custom and personal wayback machine)
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

index.html 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="fr">
  4. <!-- Has to be within the first 1024 bytes, hence before the <title>
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>HTML: The Inaccessible Parts (archive) — David Larlet</title>
  13. <meta name="description" content="Publication mise en cache pour en conserver une trace.">
  14. <!-- That good ol' feed, subscribe :). -->
  15. <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
  16. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  17. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
  18. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
  19. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
  20. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  21. <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
  22. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  23. <meta name="msapplication-TileColor" content="#f0f0ea">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f0f0ea">
  26. <!-- Documented, feel free to shoot an email. -->
  27. <link rel="stylesheet" href="/static/david/css/style_2020-06-19.css">
  28. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  29. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  30. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  31. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  32. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  35. <script type="text/javascript">
  36. function toggleTheme(themeName) {
  37. document.documentElement.classList.toggle(
  38. 'forced-dark',
  39. themeName === 'dark'
  40. )
  41. document.documentElement.classList.toggle(
  42. 'forced-light',
  43. themeName === 'light'
  44. )
  45. }
  46. const selectedTheme = localStorage.getItem('theme')
  47. if (selectedTheme !== 'undefined') {
  48. toggleTheme(selectedTheme)
  49. }
  50. </script>
  51. <meta name="robots" content="noindex, nofollow">
  52. <meta content="origin-when-cross-origin" name="referrer">
  53. <!-- Canonical URL for SEO purposes -->
  54. <link rel="canonical" href="https://daverupert.com/2020/02/html-the-inaccessible-parts/">
  55. <body class="remarkdown h1-underline h2-underline h3-underline hr-center ul-star pre-tick">
  56. <article>
  57. <header>
  58. <h1>HTML: The Inaccessible Parts</h1>
  59. </header>
  60. <nav>
  61. <p class="center">
  62. <a href="/david/" title="Aller à l’accueil">🏠</a> •
  63. <a href="https://daverupert.com/2020/02/html-the-inaccessible-parts/" title="Lien vers le contenu original">Source originale</a>
  64. </p>
  65. </nav>
  66. <hr>
  67. <main>
  68. <p>I’ve always abided in the idea that “HTML is accessible by default and then we come along and mess it up.” In a lot places this is very true and by just using a suitable HTML element instead of a generic <code>div</code> or <code>span</code> we can have a big Accessibility impact.</p>
  69. <p>But that’s not always the case. There are some cases where even using plain ol’ HTML causes accessibility problems. I get frustrated and want to quit web development whenever I read about these types of issues. Because if browsers can’t get this right, what hope is there for the rest of us. I’m trying to do the best I can, use the platform, but seems like there’s a dozen “gotchas” lurking in the shadows.</p>
  70. <p>I’m going to start rounding up those HTML shortfalls in this here post as a little living document that I can personally reference every time I write some HTML.</p>
  71. <p><hr/>
  72. <p><code>&lt;input type="number"&gt;</code><br/>
  73. Gov.UK finds <a href="https://technology.blog.gov.uk/2020/02/24/why-the-gov-uk-design-system-team-changed-the-input-type-for-numbers/">Number Inputs aren’t inclusive</a>. (2020)</p>
  74. <p><code>&lt;input type="date"&gt;</code><br/>
  75. Graham Armfield finds <a href="https://www.hassellinclusion.com/blog/input-type-date-ready-for-use/">Date Inputs not ready for use</a>. (2019)</p>
  76. <p><code>&lt;input type="search"&gt;</code><br/>
  77. Adrian Roselli points out <a href="https://adrianroselli.com/2019/07/ignore-typesearch.html">Search Inputs aren’t as useful as originally thought</a>. (2019)</p>
  78. <p><code>&lt;select multiple&gt;</code><br/>
  79. Sarah Higley tests with actual users and finds <a href="https://www.24a11y.com/2019/select-your-poison-part-2/">Select Multiple has a 25.3% success rate</a>. (2019)</p>
  80. <p><code>&lt;progress&gt;</code><br/>
  81. Scott O’Hara finds <a href="https://scottaohara.github.io/a11y_styled_form_controls/src/progress-bar/">numerous errors with the Progress element</a>. (2018)</p>
  82. <p><code>&lt;meter&gt;</code><br/>
  83. Scott O’Hara finds <a href="https://scottaohara.github.io/a11y_styled_form_controls/src/meter/">more numerous errors with the rare Meter element</a>. (2018)</p>
  84. <p><code>&lt;dialog&gt;</code><br/>
  85. Scott O’Hara declares <a href="https://www.scottohara.me/blog/2019/03/05/open-dialog.html">Dialog not ready for production</a>. (2019)</p>
  86. <p><code>&lt;details&gt;&lt;summary&gt;</code><br/>
  87. Adrian Roselli feels <a href="https://adrianroselli.com/2019/04/details-summary-are-not-insert-control-here.html">Details/Summary are only good in limited contexts</a> (e.g. <a href="https://daverupert.com/2019/12/why-details-is-not-an-accordion/">Details doesn’t work as an Accordion</a>, which is what I would expect). (2019)</p>
  88. <p><code>&lt;video&gt;</code><br/>
  89. Scott Vinkle goes with a third-party player after seeing that <a href="https://scottvinkle.me/blogs/blog/how-accessible-is-the-html-video-player">the native HTML Video Player is a very inconsistent experience for screen readers</a>. (2019)</p>
  90. <p><code>&lt;div onclick&gt;</code><br/>
  91. Technically this is JavaScript, but the screen reader <a href="https://github.com/carbon-design-system/carbon/issues/986#issuecomment-412968245">JAWS announces “Clickable” when the element or one its ancestors have a click event handler</a>. This is a bummer for trying to make tap areas bigger. (2018)</p>
  92. <p><code>&lt;div aria-label&gt;</code><br/>
  93. Paciello Group educates how <a href="https://developer.paciellogroup.com/blog/2017/07/short-note-on-aria-label-aria-labelledby-and-aria-describedby/"><code>aria-label</code>, <code>aria-labelledby</code> , and <code>aria-describedby</code> only work on certain elements… and not <code>&lt;div&gt;</code> elements</a>. It’s not very intuitive to me that <code>aria-label</code> would only work <em>sometimes</em> and it seems like something linters like <a href="https://www.deque.com/axe/">axe</a> should catch. (2017)</p>
  94. <p><code>&lt;a href&gt;&lt;div&gt;Block Links&lt;/div&gt;&lt;/a&gt;</code><br/>
  95. Adrian Roselli finds <a href="https://adrianroselli.com/2020/02/block-links-cards-clickable-regions-etc.html">Block Links in a Card UI have usability issues</a>. (2020)</p>
  96. <p><code>aria-controls</code><br/>
  97. The <code>aria-controls</code> attribute is a great way to establish a relationship between two elements and is in tons of tutorials… only one problem… Heydon Pickering points out <a href="https://heydonworks.com/article/aria-controls-is-poop/"><code>aria-controls</code> doesn’t do anything</a>. (2016)</p>
  98. <p><code>role="tablist"</code><br/>
  99. After some user testing, Jeff Smith discovered <a href="http://simplyaccessible.com/article/danger-aria-tabs/">the best way to make accessible tabs is to remove <code>role="tablist"</code>, <code>role="tab"</code>, <code>role="tabpanel"</code> from their tabs</a>. FWIW, these <a href="https://medium.theuxblog.com/danger-testing-accessibility-with-real-people-4515f72db648">findings were contested in a 3,900 word blog post by Léonie Watson</a>. (2016)</p>
  100. <hr/>
  101. <p>Your mileage may vary, test with actual users. I’ll do my best to update this as the situation evolves glacially over the next 20 years.</p>
  102. <p><em>Edit 2/28/2020:</em></p>
  103. <ul>
  104. <li>Added the year to each link to help reflect the potential “staleness” of the information.</li>
  105. <li>Added a note to test with actual users.</li>
  106. <li>Added a link to Léonie Watson’s rebuttal under the <code>tablist</code> discussion.</li>
  107. </ul></p>
  108. </main>
  109. </article>
  110. <hr>
  111. <footer>
  112. <p>
  113. <a href="/david/" title="Aller à l’accueil">🏠</a> •
  114. <a href="/david/log/" title="Accès au flux RSS">🤖</a> •
  115. <a href="http://larlet.com" title="Go to my English profile" data-instant>🇨🇦</a> •
  116. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">📮</a> •
  117. <abbr title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340">🧚</abbr>
  118. </p>
  119. <template id="theme-selector">
  120. <form>
  121. <fieldset>
  122. <legend>Thème</legend>
  123. <label>
  124. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  125. </label>
  126. <label>
  127. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  128. </label>
  129. <label>
  130. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  131. </label>
  132. </fieldset>
  133. </form>
  134. </template>
  135. </footer>
  136. <script type="text/javascript">
  137. function loadThemeForm(templateName) {
  138. const themeSelectorTemplate = document.querySelector(templateName)
  139. const form = themeSelectorTemplate.content.firstElementChild
  140. themeSelectorTemplate.replaceWith(form)
  141. form.addEventListener('change', (e) => {
  142. const chosenColorScheme = e.target.value
  143. localStorage.setItem('theme', chosenColorScheme)
  144. toggleTheme(chosenColorScheme)
  145. })
  146. const selectedTheme = localStorage.getItem('theme')
  147. if (selectedTheme && selectedTheme !== 'undefined') {
  148. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  149. }
  150. }
  151. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  152. window.addEventListener('load', () => {
  153. let hasDarkRules = false
  154. for (const styleSheet of Array.from(document.styleSheets)) {
  155. let mediaRules = []
  156. for (const cssRule of styleSheet.cssRules) {
  157. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  158. continue
  159. }
  160. // WARNING: Safari does not have/supports `conditionText`.
  161. if (cssRule.conditionText) {
  162. if (cssRule.conditionText !== prefersColorSchemeDark) {
  163. continue
  164. }
  165. } else {
  166. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  167. continue
  168. }
  169. }
  170. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  171. }
  172. // WARNING: do not try to insert a Rule to a styleSheet you are
  173. // currently iterating on, otherwise the browser will be stuck
  174. // in a infinite loop…
  175. for (const mediaRule of mediaRules) {
  176. styleSheet.insertRule(mediaRule.cssText)
  177. hasDarkRules = true
  178. }
  179. }
  180. if (hasDarkRules) {
  181. loadThemeForm('#theme-selector')
  182. }
  183. })
  184. </script>
  185. </body>
  186. </html>