🌟

【技術書まとめ】HTML解体新書

2023/10/04に公開

HTMLやWAI-ARIAの仕様について改めて学ぼうと思い読んでみた。

1: HTMLの基本概念

  • リンクをマウスでクリックするだけで、遥か彼方の国にある文書を読むことができる
  • ルール
    • 字句的ルール
      • 閉じタグがないなど
    • 語彙的ルール
      • h1やpをstrong要素の中に入れる
    • 意味論的ルール
      • 本文をh1とする
  • アクセシビリティ
    • アクセシビリティ
    • ガイドライン
      • WCAG2.1
      • サポート文書
        • Understanding WCAG2.0
        • Techniques WCAG2.0
    • WAI-ARIA
      • HTML要素に対して、支援技術に伝えるべき情報を追加する
        • roleで要素の役割
        • aria-で状態
  • URL
    • スキーム
      • https
    • ホスト
      • example.com
    • ポート
      • 3000
    • パス
      • /foo/bar.php
    • クエリ
      • ?q=xxx
    • フラグメント
      • #result
  • MIMEタイプ
    • 未設定だとブラウザが推測するMIME sniffingする
      • text/plainであるはずがHTMLと解釈させてJSを実行する脆弱性となることもある
  • HTML仕様

2: HTMLマークアップのルール

  • URL
    • 絶対URLと相対URL
      • スキーム相対URL
        • //example.com/foo/bar.html
          • http, httpsが同じになる
      • パス絶対URL
        • スキーム相対URLから//とホストを取り除いたもの
          • /foo/bar.html
      • パス相対URL
        • 先頭が/で始まらないパス
          • foo/bar.html
            • ./などを使う
    • パーセントエンコードは%に続いて2桁の16進数で文字コードを表現する
      • &はHTMLの文字参照に利用するので&とする

3: HTMLの主要な要素

  • セクション
    • article
      • そのセクションだけで自己完結するもの
        • スクリーンリーダーによってランドマークとして扱うこともある
    • section
      • <h2>などの見出しが必要
      • ランドマークではない
    • aside
      • スクリーンリーダーで任意の要素にジャンプしたり、丸ごとスキップできる
    • nav
      • 読み飛ばしやジャンプができると便利ならばnav要素にする
        • 使い過ぎには注意
    • 見出し
      • h1からh6
        • aria-levelを使うと7以上も表現できる
          • 対応していないことも多いので慎重に使用する
    • header
      • もっとも近い祖先のセクショニングコンテンツのヘッダーとみなされる
  • グルーピングコンテンツ
    • p
      • 特別な意味を持たない文のかたまりはpで問題ない
        • ARIAロールはない
    • dl
      • 当面スクリーンリーダーによるdl関連要素の扱いは安定しない
    • figure
      • 本文から参照される自己完結型のコンテンツ
        • 画像、図表、例、コード断片など
          • 本文から参考として参照されている
          • 本文から切り離しても本文の説明が成立する
          • 単独で1つのコンテンツとして成立する
      • imgのaltと同内容をfigcaptionに入れるとスクリーンリーダーで2回読み上げてしまうため注意する
  • テキストレベルセマンティクス
    • cite
      • 参考文献の正式なタイトルを示す
        • 著者名は含まない
    • time
      • 日付や時刻をマシンリーダブルな形式で表現する
        • <time datetime="2017-01-23">2017年1月23日</time>
    • data
      • 日時以外のデータをマシンリーダブルにする
    • wbr
      • その位置で改行が可能であることを表す
  • リンク関連要素
    • a
      • リンク先のコンテンツタイトルをそのままリンクテキストとするのが望ましい
        • スクリーンリーダーにおいては、「こちら」では意味をなさないから
      • 画像をリンクにするとaltがリンクテキストとなる
      • target="_blank"はテキスト内に新しいタブで開くことを明示した方がよい
      • 属性
        • target
          • _blankは新しいブラウジングコンテキストを作成する
            • window.openerで元のブラウジングコンテキストを参照できる
              • 古いブラウザではこれがクロスドメインで可能だったのでセキュリティ上の重大な注意点となっていた
        • download
          • ダウンロードファイル名のヒントとなる
        • ping
          • どこからどこにページ遷移したのか把握できる
            • HTTPリダイレクトやJSよりもパフォーマンスが高い
        • rel
          • rel="nofollow"
            • サイトオーナーがリンク先を推奨しないことを示す
          • rel="preconnect"
            • ドメインの名前解決、TCPコネクションの確立、TLSのネゴシエーションまで行う
              • リンク先URLスキームはhttp若しくはhttpsでないと無視される
          • rel="prefetch"
            • 事前にリソースを取得しキッシュさせることができる
          • rel="preload"
            • 現在のページで使用するサブリソースをキャッシュする
          • rel="prev", rel="next"
            • ブラウザはnextで指定されたリソースを先読みすることがある
  • エンベディッドコンテンツ
    • img要素
      • alt
        • altが空の場合は装飾的なものとみなされる
          • alt属性はウェブアクセシビリティにおいてもっとも重要な属性のひとつ
        • 画像をテキストに置き換えても違和感なく、内容が過不足なく伝わるように代替テキストを記述する
          • 画像と等価なテキストとする(電話口で読み上げるように)
        • 本文に説明がある場合は繰り返しを避ける
    • iframe要素
      • 提供されるHTMLコードが正しくない場合もある
        • アクセシブルかどうか確認してから用いる
  • テーブル(table
    • かつてCSSが未成熟だったときにレイアウト目的でtableが使われることがよくあった
      • アクセシビリティの観点でもやるべきではない
    • tr
      • thtdを必ず1つ以上入れる
    • th
      • scope="col"などで行か列のどちらが見出しか明示的に表す
      • abbr="割合"などで見出しが長いときに略称を付けられる
      • caption要素でテーブルタイトルや説明文を入れられる
  • フォーム
    • form要素
      • method: get, post, dialogのいずれかを指定する
        • get
          • 入力データはURLのクエリーに付与される
            • application/x-www-form-urlencodedでシリアライズされる
          • method値を省略した場合のデフォルトとなる
      • formにformを入れ子にはできない
        • 複数のボタンがあって送信先を変えるときはformaction属性を指定する
      • action: フォームの送信先となるURLを指定する
        • 指定なしの場合はフォームが配置されるページ自身が送信先となる
      • enctype: postで送信するときのリクエストボディの形式を指定できる
        • application/x-www-form-urlencoded
          • form controlの名前と値のペアをURL ecncodedして連結したもの
        • multipart/form-data
          • 入力項目それぞれをboundaryで区切った形式
            • ------WebKitFormBoundary***
        • text/plain
          • 名前=値のペアを改行(CR+LF)で区切った形式
    • label要素
      • labelとform controlとを明示的に関連づけることができる
        • for属性でidと結びつける
    • input要素
      • type属性によって変わる
        • text, search: 1行テキスト入力
        • tel
          • 改行以外のあらゆる文字を受け入れる
          • スクリーンリーダーではデフォルトはtextboxとなるので、a11yとしては電話番号入力欄であることがわかるラベルをつける
        • url
          • 絶対URL
            • HTTPやHTTPSに限られないことに注意する
              • コロンを含む文字列はほぼすべて許可してしまう
        • email
          • a11yではメールアドレスとわかるようなラベルをつける
        • password
          • 視覚的には隠されていてもスクリーンリーダーでは読み上げることがあるので注意する
        • 日付および時刻の入力
        • number
          • 入力できる値は妥当な不動小数点
            • 数字以外の文字も入力できる(., +, -, e, E
          • min, max, stepで制限できる
          • クレジットカード番号は数値だとしてもtextが適する
        • checkbox
          • チェックされたnameとvalueがフォーム送信時に送られる
            • チェックされていない場合はnameとvalueは送られない
        • radio
          • 一度でも選択されると戻すことはできない
        • file
          • enctype属性値をmultipart/form-dataにする
          • multipleで複数選択可能とする
          • acceptでファイルの種類を絞り込める
            • "audio/*"
            • "video/*"
            • "image/*"
            • パラメータのないvalidなMIMEタイプ文字列
              • text/htmlなど
            • .で始まる文字列で指定された拡張子のファイルを指定できる
              • ".doc,.docx,xml..."など
            • 想定外のファイル種類のアップロードを防ぐことはできないことに注意
        • hidden
          • システム側では値を受け取る必要があるが、ユーザーに入力・編集させる必要がないもの
          • このコントロール値は秘匿されない
            • dev toolsで読み取り書き換え可能
      • maxlength, minlength属性
        • minはそれより短い値を入れられる
          • 送信時にvalidationされる
        • maxはそれ以上入れられなくしてもよい
      • size属性
        • 見た目の幅を指定する
          • 正確な幅はCSSで指定する
        • デフォルト値は20
      • readonly属性
        • 入力を受け付けない状態とする
          • disable属性と違って、入力されている値は送信される
      • pattern属性
        • テキスト入力コントロールの値をチェックできる
          • type属性が、test, search, url, tel, email, passwordのみ
            • それ以外は指定しても無視される
        • title属性を入れておくとエラー時に表示される
          • <input pattern="[0-9]{3,4}" title="3〜4文字の数字を入力してください">
        • 値が空の場合はvalidationされない
        • セキュリティ上の意味は持たない
          • dev toolsによってpattern属性を削除できる
      • list属性
        • 定義済み候補のリストを示す
          • 値は同一文書内のdatalist要素のID
      • placeholder属性
        • 入力するとスクリーンリーダーで読み上げられなくなるのでラベルの代わりに使わない
        • デフォルトで薄い文字色だがWCAGのコントラスト比を満たさないこともある
    • フォームコントロールの共通属性
      • name属性
        • フォームコントロールに名前を与える
          • name属性がないと、そのコントロールの値は送信されない
        • 複数の要素に同じ名前を与えられる
          • chackboxやradio buttonなどは同一グループとなる
            • 送信時にはすべて個別に送信される
      • disabled属性
        • 値は送信されない
          • これがreadonlyとの違い
      • form属性
        • form要素の外にある要素を明示的に関連づけられる
          •   <form id="form01">
                <!-- さまざまな入力欄 -->
                <button>送信する</button>
              </form>
              <!-- さまざまなコンテンツ -->
              <button form="form01">送信する</button>
            
      • autocomplete属性
        • 通常ブラウザはname属性の値を参考にするが、autocomplete属性を利用すると明示的に指定できる
          • 氏名、住所、性別、クレジットカード番号、URL、メールアドレスなど
        • 4種類のトークンを組み合わせた値を指定する
          • 配送先か、請求先か:shipping, billing
          • グループ名:section-
          • 値の種類:name, nickname, country, photoなど
          • 追加の種類:電話番号に対して自宅や職場など
        • アクセシビリティが向上するので積極的に利用するとよい
          • WCAG2.1の「入力目的の特定」を満たす
  • フォーム その2
    • button要素
      • type属性
        • デフォルトはsubmit
          • フォーム送信を意図しない場合はtype=buttonにする
    • select要素
      • required属性
        • 条件を満たす必要がある
          • multipleではない
          • sizeが1である
          • 最初のoptionがoptgroupの子ではない
          • 最初のoptionのvalueが空文字である
    • option要素
      • selectdatalistとセットで扱う
      • value属性
        • フォーム送信時に送信される値
          • valueがなければ、要素の内容となっているテキストが値となる
      • label属性
        • 省略すると、要素の内容となっているテキストがラベルとなる
    • optgroup要素
      • optionをカテゴリなどでグループ化できる
    • datalist要素
      • input要素の入力補完の候補を提示できる
        • ユーザーは選択肢から選ぶことも、選択肢を無視してテキスト入力することもできる
    • textarea要素
      • type=textのinput要素と異なり、改行できる
      • rows,cols属性
        • 入力可能な行数を制限するものではない
        • rowsで行数を指定できる
          • デフォルト値は2
        • colsで1行あたりの文字数を指定できる
          • デフォルト値は20
            • 使用フォントの文字幅の平均で計算される
        • 幅や高さはCSSで上書きされる
      • wrap属性
        • 長い行の折り返しを制御する
        • デフォルト値はsoft
        • hardに指定すると改行(CR+LF, %0d%0a)が挿入される
          • GETメソッドで送信すると入る
    • output要素
      • 実行結果を表示できる
      • JSでの動的処理に適する
      • for属性
        • このoutputに関連する入力欄を示すことができる
    • progress要素
      • プログレスバー
        • <progress value="0.5">50%</progress>
    • meter要素
      • 棒グラフのようなゲージ
        • 適正範囲を指定することで表示を変えられる
    • fieldset要素
      • 一連のフォームコントロールをグループ化する
        • legend要素でラベルを付けられる
          • fieldsetの直接の子要素である必要がある
            • 装飾としてdivで囲うことはできない
        • ラジオボタンやチェックボックス使用時に何に対する選択か明確にすることができる
          • labelは個々の選択肢の名前となるだけだから
      • legendをつけて、その下はulでフォームをまとめていく使い方もある
      • 属性
        • disabled, name, form属性が指定できる
    • legend要素
      • 中にh2などの見出しも入れられる
        • divは入れられない
  • インタラクティブ要素
    • details要素
      • アコーディオンのようなもの
      • 必ずsummary要素を含む
      • open属性によって開閉する
    • summary要素
      • 見出し要素も入れられる
        • 見出しをクリックすると展開されるようにできる
        • legendは入れらないのでfieldsetには使えない
    • dialog要素
      • ダイアログボックスやサブウィンドウ
      • 子要素にmethod=dialogとしたformがある場合
        • 送信時にダイアログを閉じて、値をreturnValueプロパティから取得できる
      • JSで操作するときはshow(), showModal(), close()で操作する
        • JSでopen属性を操作するとフォーカス制御が行われない
  • スクリプティング
    • 現在のHTML仕様はJSのみを想定している
      • ブラウザ上で動作するスクリプトは事実上JSのみとなっている
    • script要素
      • 特定のセマンティクスを持たない
        • ユーザーに何かを提示するものではない
      • 終了タグは省略できない
      • type属性
        • defer,async属性
          • 読み込みタイミングを制御できる
            • 外部JSを読み込んでいる場合のみ
          • defer
            • HTML解析と並行してJSを読み込む
              • 両方終わったら実行される
                • DOMContentLoadedイベントが発生するタイミングで初めて実行される
          • async
            • HTML解析完了を待たずにJSを実行する
              • 実行開始タイミングは不定
                • HTMLソースでの出現順とは異なることもある
          • deferとasyncを同時指定するとasync挙動になる
            • async対応なしブラウザではdeferとなる
          • モジュールスクリプトでは常にdefer動作となる
      • crossorigin属性
        • srcで指定されたリソース参照のCORS挙動を制御できる
          • src属性で指定したリソースの取得を制御するだけ
            • JS内部からのCORSリクエストはwithCredentialsなどのプロパティなどの設定が必要
        • 単にcrossoriginとだけ指定すると"crossorigin-"annonymous"となる
        • "anonymous"
          • HTTP認証やCookieなどのクレデンシャル情報は同一オリジンに対してのみ送信される
            • クロスオリジンだと送信されない
        • "use-credentials"
          • オリジンに関わらずクレデンシャル情報が常に送信される
      • integrity属性
        • 「サブリソース完全性(Subresource Integrity)」の仕様に沿ってチェックできる
          • JSが改竄されていないか確認できる
            • ハッシュ値を照合する
              • base64でエンコードされたハッシュ値をハイフンでつないだ文字列
          • 外部サイトが攻撃を受けてJS改竄された場合に、読み込み側も影響を受けることを防ぐ
      • referrerpolicy属性
        • JSを参照する場合のreferrerpolicyを指定できる
    • noscript要素
      • JSが無効な場合のフォールバックコンテンツを提供できる
    • canvas要素
      • JSで任意のビットマップを描画できるキャンバスを表せる
      • インタラクティブコンテンツ(a,button,tabindexなど)を子孫要素にできない
      • 中身はcanvasが利用できないときのフォールバックコンテンツとなる
        • img要素などとする
      • width, heigh省略時は300, 150となる
      • ARIAロールがないのでセマンティクス上の意味を持たない
    • カスタム要素
      • WebComponentsを構成するものの1つ
      • 独自の要素を定義できる
        • 5つ星の評価のマークアップなど
      • 制約
        • アルファベット小文字で始まること
        • 1つ以上のハイフンを含むこと

4: 主要な属性とWAI-ARIA

  • グローバル属性
    • すべてのHTML要素に共通して利用できる属性
      • HTML仕様以外にもWAI-ARIA仕様やXML仕様もある
    • title属性
      • 要素に対するヒントや助言を表す
      • 値はユーザーに伝わらないことも多い
        • titleはツールチップ表示になるが表示できない環境も多い
    • lang属性
      • 指定された要素の自然言語を指定する
      • 値は大文字小文字を区別しない
    • style属性
      • specificityが最も高くなり、あらゆるセレクターよりも優先される
    • class属性
      • CSSやJSで使用する
      • 要素の役割や状態を伝えたい場合はARIA属性を利用する
        • [aria-pressed="true"] { /* スタイル */ }など
          • ARIA属性のみでスタイルの変化を実装できる
            • class属性は削除できる
    • id属性
      • URLフラグメント、参照、JSでの使用などで使われる
      • ASCII空白文字を除くすべての文字が使える
        • 大文字小文字は区別される
    • tabindex属性
      • その要素がフォーカスを受け取るかどうかを制御できる
        • sequential focus navigationと呼ばれる
          • DOMツリー順に移動する
        • focusableではないHTML要素をフォーカス可能にする
      • tabindex=0を指定した場合
        • focusableでなくてもフォーカスを受け取れるようになる
      • tabindex=-1を指定した場合
        • フォーカス可能になりfocus()メソッドを受け取るが、シーケンシャルフォーカスナビゲーションの対象にはならない
          • キーボード操作ではフォーカスできない
            • JSでフォーカス制御するときに使用する
      • tabindex=正の数を指定した場合
        • シーケンシャルフォーカスナビゲーションの順序が変更される
          • 数値の小さいものが優先的にフォーカスが移る
    • autofocus属性
      • 基本的に同一ページ内で1つだけ
        • ログインフォームや検索フォームしか存在しないページなど
        • dialog
    • イベントハンドラーコンテンツ属性
      • 要素のイベントが発生したときにJSを実行できる
      • イベントハンドラー属性
        • onで始まる
          • onclickなど
        • form内のbutton要素のonclickはsubmitしてしまうので、type=buttonと指定する
      • イベントハンドラー属性を使用しないイベント定義
        • イベントリスナーを設定する
          • button.addEventListener('click', ...)など
    • accesskey属性
      • ユーザーエージェントに対してショートカットキーのヒントを与える
        • <button type="button" accesskey="1"...
        • 修飾キーとの同時押し(alt+1など)
      • アクセシビリティ観点では利用を避ける方が好ましい
        • 操作のバッティングや挙動の不安定さなど
    • hidden属性
      • 現時点でこのページと無関係であることを示す
        • 子要素もまとめてレンダリングしなくなる
        • スクリーンリーダーでも読み上げられなくなる
    • カスタムデータ(data-*)属性
      • 任意の要素に任意の属性を指定できる
        • 主にJSから参照する
          • 属性名から先頭のdata-を除去したものがプロパティ名となる
            • *部分にハイフンを含むときはキャメルケースでアクセスできる(data-html-book -> htmlBook
            • 数字で始めると.でアクセスはJS構文エラーとなる(data-0
  • WAI-ARIA
    • W3CのWAIによって発行されている仕様
      • アクセシビリティ向上のための属性を定義している
        • 組み合わせる相手のマークアップ言語をホスト言語(host language)と呼ぶ
    • ARIA属性の分類
      • ロール(role)
        • 要素の役割を表す
          • 何か、何もするものか
            • role="navigation"など
          • 対応するHTML要素がない場合もある
      • ステート(state)
        • 要素の現在の状態を表す
          • 頻繁に変化することが想定されるもの
            • aria-disabled="true"など
              • 現在無効になっている
      • プロパティ(property)
        • 要素の性質や特性を表す
          • aria-required="true"など
          • stateとの違いは厳密なものではない
    • WAI-ARIAとその周辺仕様
      • WAI-ARIA仕様
        • WAI-ARIAそのものの説明と、ロール、ステート、プロパティの定義
      • ARIA in HTML
        • HTMLをホスト言語とした場合のARIAの位置付けを規定している
      • Using ARIA
        • W3Cのワーキンググループノート
      • WAI-ARIA Authoring Practices
        • W3Cのグループノート
        • 本格的なウィジェットの実装例が紹介されている
    • role属性
      • 要素のロールを指定する
      • ASCII空白文字で区切って複数指定できる
        • フォールバックのためなので、適用可能な先頭が適用される
        • <div role="dummyrole blockquote ...">...</div>
      • 抽象ロールは指定できない
      • ロールの上書き
        • ホスト言語がもともと持つロールを「暗黙のネイティブロール(inplicit native role)」と呼ぶ
          • role属性で上書きできる
        • <a href="/register" role="button">...</a>
          • link -> button に上書きしている
        • 上書きするのはセマンティクスだけ
          • 機能は変更しない
            • スペースキーでボタンを押せるようにはならない
        • ネイティブロールを上書きできるが、機能と矛盾するような指定はできない
          • button -> heading など
      • 特殊な働きをするロール
        • ランドマークロール
          • ナビゲーションランドマークとして機能するもの
            • mainまで読み飛ばすなどができる
        • ライブリージョンロール
          • live regionは内容が更新された際にユーザーに通知される領域
      • ロールの削除
        • presentationロール, noneロール
          • ネイティブロールを打ち消すロール
            • タブコンポーネントの親子のロール関係を修復したいなど
      • 必須の所有要素が存在する場合のロール変更
        • 親要素のロールだけを変更すると矛盾してしまう
    • 代表的なaria-*属性
      • aria-hidden属性(state)
        • true or falseを指定する
        • アクセシビリティAPIに公開されず、支援技術からアクセス不可となる
          • 意味を持たないアイコンをアイコンフォントで表現するときなど
      • aria-label属性(property)
        • 要素にラベル付けする文字列を定義する
          • "X"を閉じるボタンとしたときにaria-label="閉じる"とするなど
            • 「エックスボタン」ではなく「閉じるボタン」と読み上げるようになる
        • aria-labelの使いすぎに注意
        • 名前付けできないロールもある
          • spanなど
      • aria-labelledby属性(property)
        • 属性値にラベルを含む要素のIDを指定する
          • aria-labelledby="billing name"
            • 元あったラベルは上書きされる
      • aria-describedby属性(property)
        • 使い方はaria-labelledbyとほとんど同じ
          • 説明を付与できる
      • aria-current属性(state)
        • current itemであることを示せる
          • 「現在のページ」と読み上げるなど
      • aria-haspopup属性(property)
        • 指定した要素がポップアップする何かを持っていることを示せる
      • aria-expanded属性(state)
        • expandするかや開閉状態を示せる
      • aria-controls属性(property)
        • aria-expandedと組み合わせて使う
      • aria-level属性(property)
        • 見出しレベルを示す
          • h7も表現できる
      • aria-live属性(propetry)
        • 要素をライブリージョンとして定義できる
          • 動作を変更できる
            • 挙動変更は推奨されない
        • リアルタイム通知や部分的更新などで使用される
      • aria-atomic属性(property)
        • ライブリージョンに変更があったときに差分だけを通知するかどうか設定できる
          • falseだと、時計の値が17:33 -> 17:34となったときは4のみ通知される
          • デフォルトはtrue
  • ARIA利用時の注意点
    • 誤用や使いすぎに注意する
      • 「ARIAを使う際にもっとも注意すべきことは、ARIAを使わないようにすることです」
    • 基本的な注意点
      • まずHTML自身の機能を利用する
    • 冗長なロールやARIA属性を使用しない
      • <main role="main">など
      • ネイティブセマンティクスをむやみに変更しない
        • <h2 role="tab">など
          • <div role="tab"><h2>見出しタブ</h2></div>とする
    • インタラクティブコンテンツを扱う際の注意点
      • マウスやタッチで操作可能なものはキーボードでも操作可能にする
        • WAI-ARIAは機能は追加しないので注意
      • 操作可能な要素を隠さない
        • フォーカス可能な要素にaria-hidden="true"などをつけない
    • アクセシブルな名前を与える方法
      • 要素のテキストや、画像のaltなどがアクセシブルな名前となる
    • 操作可能でない要素にアクセシブルな名前を与える
      • ランドマークに名前を与える
        • <nav aria-label="パンくずナビゲーション">
          • 複数navがある場合に区別できるようになる
    • ARIA実装時の基本テクニック
      • アクセシブルな名前を提供する方法
        • テストを行い、警告に注意する
        • 可視のテキストを使う
          • フローティングラベル手法で可視のラベルテキストを確保できる
        • HTMLのネイティブ機能を使う
        • ブラウザーのフォールバックに頼ることは避ける
        • 簡潔で有用な名前を付ける
      • スクリーンリーダー向けテキストを提供する
      • キーボードフォーカスを制御する
        • フォーカスを当てた後に何か操作させたいときはJSで実装する
    • 動作検証とアクセシビリティサポーテッド
      • スクリーンリーダーによって動作検証する
        • フィードバックとして利用ユーザーの意見を聞く
  • WAI-ARIAの実践
    • 事例1: divで開閉buttonを作ったハンバーガーメニュー
      • どう改善するか
        • キーボード操作を可能にする
          • divではフォーカスが当てられない
            • 方法1: button要素とする
            • 方法2: a要素を使用する(非推奨)
              • role=buttonとしてもボタンと同じ挙動にはならないので可能な限りbutton要素を使用すべき
            • 方法3: divのままキーボード操作可にする(非推奨)
              • tabindex=0 role=buttonとして、JSでkeypressイベントをつける
        • 何のボタンかわかるようにする
          • 方法1: 画像をimg要素にしてaltをつける
          • 方法2: スクリーンリーダー用テキストを入れる
          • 方法3: aria-labelを利用する
          • 方法4: aria-huspopupを利用する
        • メニューの開閉状態がわかるようにする
          • 方法1: 開いたメニューにフォーカスを移す
          • 方法2: ボタンのラベルで状態を伝える
          • 方法3: aria-expandedを利用する
        • メニューの裏側にフォーカスが当たらないようにする
          • 方法1: メニューの外の要素をすべてフォーカス不可にする
          • 方法2: フォーカス移動するときにメニューの先頭に戻す
            • メニューの最後の要素にkeypressイベントをつけるなど
          • 方法3: フォーカス移動しようとした場合にメニューを自動的に閉じる
    • 事例2: カルーセルのライブラリーを選定する
      • キーボード操作可能か
        • フォーカスが明確に見えるかどうかも確認する
      • フォーカス時のローテーション停止
      • スクリーンリーダーで操作できるか
      • 他の箇所の読み上げを妨害しないか
        • カルーセルがライブリージョンとして扱われるなど
          • ローテーションごとに読み上げられる
      • ローテーションコントロールがあるか
    • 事例3: タブのマークアップを検討する
      • tab, tablist, tabpanelはHTMLネイティブ要素にはない
        • role属性で指定する
      • タブ
        • aまたはbutton要素を使う
          • <button type="button" role="tab" id="tab01" aria-controls="tabpanel01" aria-selected="true">タブその1</button>など
            • JSでaria-selected=truetabindex=-1を操作する
      • タブリスト
        • どの要素を採用するかは議論の余地がある
          • menu, ol, ul, navなど
          • WAI-ARIA Authoring Practicesではdiv要素を使用している
      • タブパネル
        • sectiondiv
      • タブの操作方法をあえて実装しない選択もある
        • ただ省スペース化するだけならulとページ内リンクでもいい
    • 事例4: モーダルダイアログ
      • dialogは対話なので、ユーザー操作を受け付けない通知領域はdialogとは呼ばない
      • WAI-ARIAを駆使した実装
        • divにrole=dialogを指定する
        • tabindex=0でフォーカストラップを行う
    • 事例5: インラインSVGのアクセシビリティを担保する
      • svg要素はデフォルトのロールがimg要素とは異なる
        • graphics-documentロール
        • 画像ならrole=imgと指定する
    • 画像の代替テキストと説明を提供する
      • インラインでSVGを使用するとき
        • 画像の代替テキストと説明文をSVGの中で与えるようにする
      • 装飾的なSVG画像を無視させる
        • aria-hidden=trueとする
          • img要素のalt=""と同じ

Discussion