Upgrade to Pro — share decks privately, control downloads, hide ads and more …

the past and future of accessible front-end development

D65ac1a4aacb7a449bb61cef10fb7143?s=47 Okuto Oyama
November 27, 2021

the past and future of accessible front-end development

JSConfJP 2021
「アクセシブルなフロントエンド開発のこれまでとこれから」発表資料

登壇情報ページ

D65ac1a4aacb7a449bb61cef10fb7143?s=128

Okuto Oyama

November 27, 2021
Tweet

Transcript

  1. ΞΫηγϒϧͳ ϑϩϯτΤϯυ։ൃͷ ͜Ε·Ͱͱ͜Ε͔Β େࢁԞਓɹ+4$POG+1 2021 - 2021/11/27

  2. ࣗݾ঺հ

  3. େࢁԞਓʢ͓͓΍·͓͘ͱʣ • he/him • גࣜձࣾΫϥ΢υϫʔΫε • ϓϩμΫτຊ෦ ϓϩμΫτ։ൃ෦ 
 ϓϥοτϑΥʔϜ։ൃ̏άϧʔϓ

    • ࣗশϑϩϯτΤϯυσβΠφʔ • ΞΫηγϏϦςΟܒ໤΍OSSίϯτϦ Ϗϡʔτ׆ಈΛ͍ͯ͠·͢ • Ұࣇͷ෕
  4. ΠϯλʔωοτΞΠσϯςΟςΟɿyamanoku

  5. ຊ೔͓࿩͢Δ͜ͱ • ΞΫηγϏϦςΟͱ͸Կ͔ • ͜Ε·ͰͷΞΫηγϏϦςΟରԠ • ͜Ε͔ΒͷΞΫηγϏϦςΟରԠ • ظ଴͍ͯ͠ΔΞϓϩʔν

  6. ̍. ΞΫηγϏϦςΟͱ͸Կ͔

  7. ΞΫηγϏϦςΟ

  8. ͋ΒΏΔਓ͕ ΞΫηεͰ͖ΔΑ͏ʹ͢Δ

  9. ΢ΣϒΞΫηγϏϦςΟ

  10. ΢ΣϒΞΫηγϏϦςΟʛ֎຿ল “ϗʔϜϖʔδΛར༻͍ͯ͠Δશͯͷਓ͕ɺ ৺਎ͷ৚݅΍ར༻͢Δ؀ڥʹؔ܎ͳ͘ɺ ϗʔϜϖʔδͰఏڙ͞Ε͍ͯΔ৘ใ΍ػೳʹ ࢧোͳ͘ΞΫηε͠ɺར༻Ͱ͖Δ͜ͱ”

  11. Press Release: W3C Launches International Program Of fi ce for

    WAI “The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect.”
  12. ΢ΣϒʹΞΫηγϒϧ

  13. ଟ༷ͳϢʔβ૚Λߟྀ͢Δ

  14. ༷ʑͳίϯςΩετ͕ଘࡏ͢Δ • ૢ࡞Ͱ͖ΔσόΠε͕ෳ਺ଘࡏ͢Δ • αʔϏεΛ࢖ͬͯ΋Β͏ঢ়گɾ؀ڥ΋ҟͳΔ • ͳΜΒ͔ͷো֐͕͋Γૢ࡞͕༰қʹͰ͖ͳ͍৔߹΋͋Δ • ΞΫηγϏϦςΟΛҙࣝ͢Δͱߟྀ͢Δίετ΋ݮΒͤΔ

  15. ΞΫηεͰ͖Δ૚Λ૿΍͢

  16. ҰਓͻͱΓ͕Ͱ͖ΔΑ͏ʹͳΔ

  17. None
  18. ࠜڌͷ͋Δ σβΠϯΛͭ͘Δ

  19. yamanoku.github.io/EXPLAINING_PORTFOLIO_SITE_ja.md “ϝΠϯίϯςϯπͷ࠷େ෯͸80chʹઃఆ͍ͯ͠·͢ɻch͸ νΣʔϯͱݺ͹ΕɺจࣈͷαΠζʹΑͬͯՄม͢Δ୯ҐͰ ͢ɻ ͜ͷઃఆʹ͢Δ͜ͱͷϝϦοτͱͯ͠ɺ௕จ͕ಡΊͳ͍ಡࣈ ো֐ͷར༻ऀͷαϙʔτ͕Ͱ͖ͨΓɺจࣈαΠζ͕େ͖͘ͳ ΔʹैͬͯςΩετͷҰ෦͕͚ܽͯಡΊͳ͘ͳΔΑ͏ͳࣄଶ ΋ൃੜ͠ʹ͘͘ͳΓ·͢ɻ”

  20. ຽؒاۀ΁ͷ ߹ཧత഑ྀͷఏڙٛ຿

  21. ຽؒࣄۀऀʹ΋ো֐഑ྀٛ຿෇͚ɹվਖ਼ࠩผղফ๏੒ཱ ʛ ڞಉ௨৴ “ো֐͕͋ΔਓͷҠಈ΍ҙࢥૄ௨Λແཧͷͳ ͍ൣғͰࢧԉ͢Δʮ߹ཧత഑ྀʯΛاۀ΍ళ ฮͳͲͷຽؒࣄۀऀʹٛ຿෇͚Δվਖ਼ো֐ऀ ࠩผղফ๏͕28೔ͷࢀӃຊձٞͰશձҰகͰ Մܾɺ੒ཱͨ͠ɻ”

  22. ো֐Λཧ༝ͱ͢Δࠩผͷղফͷਪਐʹؔ͢Δجຊํ਑ - ಺ֳ෎ “๏͸ɺෆಛఆଟ਺ͷো֐ऀΛओͳର৅ͱͯ͠ ߦΘΕΔࣄલతվળાஔʢதུʣʹ͍ͭͯ͸ɺ ݸผͷ৔໘ʹ͓͍ͯɺݸʑͷো֐ऀʹରͯ͠ߦ ΘΕΔ߹ཧత഑ྀΛత֬ʹߦ͏ͨΊͷ؀ڥͷ੔ උͱ࣮ͯ͠ࢪʹ౒ΊΔ͜ͱͱ͍ͯ͠Δɻ”

  23. ΞΫηγϏϦςΟߟྀ͕ ͞Ε͍ͯΔ͜ͱΛ஌Δ

  24. ΢ΣϒΞΫηγϏϦςΟࢼݧ݁Ռʢ2021೥౓ʣ 
 ౦ژ౎ ৽ܕίϩφ΢Πϧεײછ঱ରࡦαΠτ

  25. ̎. ͜Ε·Ͱͷ ΞΫηγϏϦςΟରԠ

  26. ͜Ε·ͰͷΞΫηγϏϦςΟରԠ • ηϚϯςΟΫεϚʔΫΞοϓΛ஧࣮ʹ • HTMLΛਖ਼͘͠࢖͏ • ෳࡶ͞͸ WAI-ARIA Ͱิࠤ͍ͯ͘͠

  27. ηϚϯςΟΫε ϚʔΫΞοϓ

  28. ηϚϯςΟΫεϚʔΫΞοϓ • ҙຯ࿦ͱͯ͠ͷදݱΛѻ͏Α͏ʹ͢Δ • ϚγϯϦʔμϒϧʹͳΔ • ࢧԉٕज़ʹ఻ΘΔΑ͏ʹม׵Ͱ͖Δ • ίϯςϯπҠಈ͢ΔͨΊͷΠϯλϑΣʔεʹ΋͋Δ •

    SEOͷ൑ఆʹ΋༏Ґੑ͕͋Δ
  29. HTML Λਖ਼͘͠࢖͏

  30. Use button, not div

  31. ͳͥ button Λ࢖༻͢Δͷ͔ • ΢Σϒϒϥ΢β্ͰͷϢʔεέʔεΛදݱ͢Δ • UAσϑΥϧτελΠϧγʔτͰݟͨ໨͕ิ͑Δ • ΫϦοΫ΍ΩʔϘʔυૢ࡞ •

    ϑΥʔΧε؅ཧ • ద੾ͳϚʔΫΞοϓͰ͸ͳ͍ͱϢʔεέʔεΛิ͑ͳ͍
  32. HTML Λਖ਼͘͠࢖͏ͨΊʹ • Nu Html Checker Λ௨ͯ͡ߏจΤϥʔͷ֬ೝΛ͢Δ • ೖΕࢠؔ܎Λཧղͯ͠࢖༻͢Δ •

    ࢧԉٕज़ʹ௨͡ΔϚʔΫΞοϓ • CSS͕ͳͯ͘΋ҙຯ͕ཧղͰ͖ΔΑ͏ʹͳ͍ͬͯΔ
  33. WAI-ARIA

  34. https://wicg.github.io/aom/explainer.html

  35. https://www.w3.org/TR/wai-aria-practices-1.1/examples/tabs/tabs-1/tabs.html

  36. WAI-ARIA Authoring Practices 1.1 “No ARIA is better than Bad

    ARIA”
  37. ̏. ͜Ε͔Βͷ ΞΫηγϏϦςΟରԠ

  38. ͜Ε·ͰͷରԠ΋ܧଓ

  39. UI ͷ੍ޚ؅ཧ

  40. ϑΥʔΧεϚωδϝϯτ

  41. Tab Focus

  42. https://www.w3.org/TR/wai-aria-practices-1.1/examples/dialog-modal/dialog.html

  43. https://crowdworks.jp/login

  44. Sigle Page Application

  45. ONLY index.html

  46. ϑϩϯτΤϯυଆͰ ঢ়ଶΛ؅ཧ͢Δ

  47. ϖʔδʹ͋Δ ঢ়ଶΛมԽͤ͞Δ

  48. None
  49. εΫϦʔϯϦʔμʔ Ͱ͸ Ͳ͏ௌ͑͜Δͷ͔

  50. None
  51. 🙄

  52. None
  53. 🤔

  54. Ͳ͏ղܾ͢Ε͹͍͍͔ʁ

  55. ARIA ϥΠϒϦʔδϣϯ

  56. ֤ϑϨʔϜϫʔΫͷ ରԠΛݟͯΈΔ

  57. Next.js

  58. RouteAnnouncer const { asPath } = useRouter( ) const [routeAnnouncement,

    setRouteAnnouncement] = React.useState('' ) const initialPathLoaded = React.useRef(false ) React.useEffect ( () => { if (!initialPathLoaded.current) { initialPathLoaded.current = tru e retur n } if (document.title) { setRouteAnnouncement(document.title ) } else { const pageHeader = document.querySelector('h1' ) const content = pageHeader?.innerText ?? pageHeader?.textConten t setRouteAnnouncement(content || asPath ) } } , [asPath ] )
  59. GatsbyJS

  60. SvelteKit

  61. svelte-announcer {#if mounted } <div id="svelte-announcer" aria-live="assertive" aria-atomic="true" > {#if

    navigated } {title } {/if } </div > {/if }
  62. Angular

  63. Async Pipe <div *ngIf="title$ | async as title" aria-live="polite" >

    <span [attr.aria-label]="title"></span > </div >
  64. LiveAnnouncer @Component( { selector: "app-component " providers: [LiveAnnouncer ] }

    ) export class AppComponent { constructor(liveAnnouncer: LiveAnnouncer) { liveAnnouncer.announce("live region!") ; } }
  65. Vue.js

  66. vue-announcer { name: 'home' , path: '/' , component: Home

    , meta: { announcer: { // vue-announcer setting s message: 'ϗʔϜը໘ ' } } }
  67. None
  68. 👍

  69. ཹҙ͢Δ͜ͱ

  70. ಡΈ্͛Δ༻్Λཧղ͢Δ • ௨஌͸ૢ࡞ͷ౎౓ೖͬͯ͘ΔͱϢʔβମݧΛଛͶΔ • جຊతʹ͸ aria-live=“polite” Ͱ௨஌ͤ͞Δ • ݱࡏਐߦதͷಡΈ্͕͛׬ྃͰ͖͔ͯΒ௨஌͞ΕΔ •

    ۓٸੑͷߴ͍ϝοηʔδ͸ aria-live=“assertive” Ͱ௨஌ͤ͞Δ • role=“alert” ΋༗༻
  71. ̐. ظ଴͢ΔΞϓϩʔν

  72. https://docs.microsoft.com/ja-jp/lifecycle/faq/internet-explorer-microsoft-edge

  73. ϒϥ΢β͸ υΩϡϝϯτϏϡϫʔ

  74. ϋΠύʔςΩετͱͯ͠ͷ HTML

  75. GUI ͱͯ͠ͷ HTMLʁ

  76. None
  77. ࢲ͕ظ଴͢Δ΋ͷͷ঺հ

  78. React GUI

  79. React GUI • React DOM ޲͚ͷ GUI πʔϧΩοτ • υΩϡϝϯτϏϡϫʔ্ͰGUIΛදݱ͍ͤͨ͞

    • React Native for Web ͔Βͷܥේ • React Native ύʔπΛ࢖༻ͯ͠ Web ্Ͱදݱ͢Δ • RN for Web ͸Twitter Liteʢݱ Twitter WebʣͰ࢖༻
  80. σβΠϯγεςϜ ͔Βͷൃ૝

  81. Headless UI

  82. Headless UI • Tailwind Labs ։ൃ • ݟͨ໨Λ࡞͍ͬͯͳ͍ UI ϥΠϒϥϦ

    • Tailwind CSS ͳͲͰఆٛͰ͖Δ • React.js ͱ Vue3 ͷΈରԠ
  83. React Aria

  84. React Aria • Adobe ։ൃ • React Spectrum σβΠϯγεςϜΛߏ੒͢Δ̍ཁૉ •

    UIͱͯ͠ͷڍಈɺΞΫηγϏϦςΟ࣮૷Λ Hooks Ͱ෼཭ • React.js ͷΈରԠ
  85. JavaScript ʹ ৼΔ෣͍Λू໿ͤ͞Δ

  86. React A11y & TailwindCSS let { buttonProps, isPressed } =

    useButton(props, ref) ; let { focusProps, isFocusVisible } = useFocusRing() ; let className = classNames ( props.isDisabled ? "bg-gray-400" : isPressed ? "bg-blue-700" : "bg-blue-500" , "text-white", "font-bold" , "py-2", "px-4" , "rounded" , "cursor-default" , "focus:outline-none" , isFocusVisible ? "shadow-outline" : "" , "transition", "ease-in-out", "duration-150 " );
  87. useNumberField function NumberField(props) { let {locale} = useLocale() ; let

    state = useNumberFieldState({...props, locale}) ; let inputRef = React.useRef() ; let incrRef = React.useRef() ; let decRef = React.useRef() ; let { labelProps, groupProps, inputProps, incrementButtonProps, decrementButtonProps } = useNumberField(props, state, inputRef) ; let {buttonProps: incrementProps} = useButton(incrementButtonProps, incrRef) ; let {buttonProps: decrementProps} = useButton(decrementButtonProps, decRef) ; return ( <div > <label {...labelProps}>{props.label}</label > <div {...groupProps} > <button {...decrementProps} ref={incrRef} > - </button > <input {...inputProps} ref={inputRef} / > <button {...incrementProps} ref={decRef} > + </button > </div > </div > ) ; }
  88. ৽ͨͳΔ ϢʔεέʔεΛ ૑଄͢Δ

  89. Custom Elements

  90. <toggle-button />

  91. Custom Elements Λੜ੒͢Δ class ToggleButton extends HTMLElement {
 connectedCallback() {

    this.setAttribute("role", "button") ; this.setAttribute("aria-pressed", “false") ; this.addEventListener("click", togglePressed) ; this.addEventListener("keydown", function (event) { if (event.key === "Enter" || event.key === "Space") { togglePressed() ; } }) ; } } customElements.define("toggle-button", ToggleButton);
  92. DOMͰදࣔ͞ΕΔͱ͖͢΂ͯݱΕΔ <toggle-button role=“button” aria-pressed="false" > Toggl e </toggle-button > <button

    > Default Butto n <button>
  93. Accessibility Object Model

  94. Custom Element & AOM Ͱදݱ͢Δ class ToggleButton extends HTMLElement {

    constructor() { super() ; this._internals = this.attachInternals() ; this._internals.role = "button";
 this._internals.ariaPressed = false ; } } ToggleButton.addEventListener('keydown', (event) => { if (event.key === "Enter" || event.key === "Space") { toggleButton() ; } }) ; customElements.define("toggle-button", ToggleButton);
  95. <button> ͷΑ͏ʹӅṭ͞ΕΔ <toggle-button > ɹToggl e </toggle-button > <button >

    Default Butto n <button>
  96. ࣗΒͰఆ͍ٛͯ͘͠

  97. ੍໿͕͋ΔͨΊ ۜͷ஄ؙͰ͸ͳ͍

  98. ࠓޙ΋ಈ޲Λ௥͍ͭͭ

  99. ঢ়گ΍ Ϣʔεέʔεʹ߹Θͤͯ ׆༻Ͱ͖ΔΑ͏ʹ

  100. ͓ΘΓʹ

  101. ΞΫηγϏϦςΟରԠ

  102. ΢ΣϒΞΫηγϏϦςΟͷ̐ݪଇ

  103. ΢ΣϒΞΫηγϏϦςΟͷ̐ݪଇ 1. ஌֮Մೳ 2. ૢ࡞Մೳ 3. ཧղՄೳ 4. ݎ࿚

  104. ΢ΣϒΞΫηγϏϦςΟͷ̐ݪଇ 1. ஌֮Մೳ 2. ૢ࡞Մೳ 3. ཧղՄೳ 4. ݎ࿚

  105. ஌֮Ͱ͖ΔΑ͏ʹ͢Δ

  106. ৮ΕΔ΋ͷΛͭ͘Δ

  107. ৮ΕΔͱ͍͏͜ͱ͸ ͦ͜ʹԿ͔͕͋Δͱ ؾ෇͚Δ

  108. ख͕͔ΓΛ࡞Δ͜ͱ͕ ΞΫηγϏϦςΟ ରԠͷҰาʹͳΔ

  109. ͔͔̌̍ͷ࿩͡Όͳ͍

  110. ৮ΕΔ΋ͷΛ ࡞͍ͬͯ͜͏

  111. ͋ΒΏΔਓ͕ ࢀՃͰ͖ΔΑ͏ʹ ͳΔͨΊʹ

  112. ΞΫηγϒϧͳ ϑϩϯτΤϯυ։ൃΛ ΍͍ͬͯ͜͏

  113. ͜Ε·Ͱ΋ ͦͯ͠ ͜Ε͔Β΋

  114. ΞΫηγϒϧͳ ϑϩϯτΤϯυ։ൃͷ ͜Ε·Ͱͱ͜Ε͔Β େࢁԞਓɹ+4$POG+1 2021 - 2021/11/27

  115. ͋Γ͕ͱ͏͍͟͝·ͨ͠