Open7
MDN Web Docsのアクセシビリティガイドを読む
アクセシビリティとは
- 可能な限り多くの人にサイトを利用してもらう。
- モバイルデバイスの人、ネットワークが遅い人などを含む
- 対応することによる利益
- semantic HTMLによりSEOが改善する
- 公的イメージが良くなる
- サイトがより使いやすくなる
- 場所によっては法律で対応が義務付けられている
不利な条件と、その支援技術の例
- 視覚障碍 (世界中で 2 億 8500 万人が視覚障碍者で、うち 3900 万人が全盲で 2 億 4600 万人がロービジョン)
- ズーム機能
- スクリーンリーダー
- 聴覚障碍 (世界中で 4 億 6,600 万人が日常生活に支障を来すほどの聴覚障碍)
- テキストによる代替手段 (動画キャプション、文字起こし)
- 運動障碍 (マウス使えないなど。肉体的な機能障碍のある大人の割合は、16.1%)
- キーボード操作になる (tabキーとか)
- 認知障碍 (知的障碍、加齢による記憶困難、精神疾患、学習障碍)
- コンテンツを2つ以上の方法で(e.g., 文字スピーチ、動画)配信
- 簡単に理解でき、重要なものがパッと見てわかるコンテンツ
- なじみの要素(共通認識)を使う
- 認証を簡単にする
- フォームを簡単にする、進捗を示してあげる
アクセシビリティの実装
- 後付けでやろうとするとコスト高い。最初からプロジェクトで検討すべき。
- アクセシビリティテスト(e.g., キーボードやタッチ操作できるか、スクリーンリーダ使えるか、コンテンツの動的な更新を視覚障碍者がわかるか)を頻繁に行う
- ただし100%は難しい。例えば、完全に視覚的なアートを視覚障碍者に大してアクセス可能にするのは不合理
ガイドラインと法律
- W3CのWeb Content Accessibility GUidelines (WCAG)。長大ではじめから読むのは難しい
- EU、米国など地域ごとに法律がある
アクセシビリティのAPI群
- ブラウザは、支援技術(AT)に役立つ情報を公開する、OSのアクセシビリティAPIを使っている。この情報は、アクセシビリティツリーと呼ばれる情報のツリーで構成される。
- macOSだとNSAccessibilityというAPI
- ウェブアプリでHTMLのネイティブな意味論的情報が足りない場合は、WAI-ARIAの機能でこれを補うことができる。これにより、アクセシビリティツリーに意味論的情報が追加される。
HTML: アクセシビリティの基礎
HTMLとアクセシビリティ
semantic HTMLの重要性
- divでなんでも書かない。
- 例えば、button要素はdivと違ってtab移動できるし、スペース、enterキーなどでボタンをアクティブにできる
- semantic HTMLには、アクセシビリティ以外の利点もある
- 開発しやすい: 開発者にとっても読みやすい。tab移動とか、便利機能がそのまま使える。
- モバイル対応に優れている: レスポンシブにするのが簡単。無駄なJSとかいらないのでファイルサイズ小さい
- SEOが良い: 単なるdivよりも見出しやリンクタグの方が、検索エンジンでキーワードとして重みがつけられているため、良い
良いセマンティクス
テキストコンテンツ
- 見出し、段落、リストなどのコンテンツ構造には、h1, h2,... p, ol, li などをきちんと使う
- これにより、スクリーンリーダーが見出しと段落を区別できたり、見出しn一覧を取り出せたり、見出しジャンプできたりする。
- 明確な言葉を使う
- 俗語、ジャーゴンを避ける。
- 認知障害、非母語話者、年少者の助けになる。
- スクリーンリーダのために、JanではなくJanuaryと書くなど略語を避ける。どうしても略語使いたければ、説明を入れる。その際abbrタグを使う
ページレイアウト
- 古くは、table系のタグを使って、表じゃないのに無理やりレイアウトをそれっぽくしてたことがあったらしい。これは当然NG
- 今はCSSでいろいろできるのでそれでやる
- レイアウトには、header, nav, main, article, aside, footerなど、意味的要素を入れると良い。
- スクリーンリーダーが追加の意味をユーザーに提供できる
UIコントロール
- UIコントロール: ボタン、リンク、フォームのこと
- これらの要素は、ブラウザがキーボード操作が可能にしてくれている
- タブキーで移動、enterでリンク開く、ボタン押す、select要素でスペース押すと選択肢表示できる
- divとかでやるとこの恩恵が得られない。
- 無理やりdivをタブ移動可能にするには、
tabindex="0"
を属性として指定する必要がある。- tabindexを1, 2,...など正の値にすると、その順にフォーカスが当たるようになるが、これは混乱の元になるので基本的にやってはいけない。基本的に0 or -1を指定する。
- tabindex="0"は、ソースコードの記述順でフォーカスを当てる、通常の使い方
- tabindex="-1"は、タブキー移動だけではフォーカスを当てたくないが、JSなどでフォーカスしたい時に使う。
- また、無理やりdiv要素でenter押した時にボタンを押すようにするには、JSでonclickイベントのハンドラをかく必要がある。
- UIコントロールに意味のあるテキストラベルをつけるのは大事
- ボタンやリンクのテキストとして、「こちら」とか意味の薄い言葉をつけてしまうと、スクリーンリーダーで読み上げた時に意味不明になりがち。「xxxについてもっと知る」みたいに明示すると良い
- フォームには、ちゃんと
<label>
要素をつけること。そうしないと、スクリーンリーダーで入力フィールドに対する説明が提供できない。また、labelをつけておくと、labelクリック時に当該フォームをactiveにできるため、ユーザーがフォームを選択しやすくなる
<div> <label for="name">名前を入れてください:</label> <input type="text" id="name" name="name"> </div>
アクセシブルなデータ表
- スクリーンリーダーのユーザーが表の構造を理解できるようにする
-
<th>
要素で見出しを明示する。加えて、scope
属性でその見出しが行に対するものか列に対するものかを明示する -
<caption>
要素で表に対する要約を明示する
-
- 良い例
<body>
<table>
<caption>A summary of the UK's most famous punk bands</caption>
<thead>
<tr>
<th scope="col">Band</th>
<th scope="col">Year formed</th>
<th scope="col">No. of Albums</th>
<th scope="col">Most famous song</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Buzzcocks</th>
<td>1976</td>
<td>9</td>
<td>Ever fallen in love (with someone you shouldn't've)</td>
</tr>
...
代替テキスト
- テキストコンテンツは基本的にアクセシブル。
- ただ、画像や動画は視覚障碍者には見えず、動画と音声は聴覚障碍者には聞こえない。
- ここでは、
<img>
要素に対する代替テキストを見ていく。-
alt
属性をつける- 説明を画像につけることができる。
- 簡潔にすることを意識する。ユーザーの理解の助けにならないような説明はつけない。
- 純粋に視覚的装飾の画像には、空のalt属性をつけることもできる(空にせずalt属性なしにすると、スクリーンリーダーがURLを読み上げてしまう)。または、
role="presentation"
をつけても同様の効果がある
-
title
属性をつける- alt属性からはみ出すような、重要度の低い補助的な情報を追加できる。
- ホバーするとtitle属性の値がツールチップで出てくる
-
aria-labelledby
属性と、別の説明要素を使う- 下記のように、pタグなどで説明をつけ、そのidをaria-labelledbyで指定する。こうすることで、複数の画像に対して同じテキストをラベルとして使用できる
<img src="dinosaur.png" aria-labelledby="dino-label" /> <p id="dino-label">The Mozilla red Tyrannosaurus…</p>
-
- figureとfigcaption
- 任意の図(imgじゃなくてもいい)と、そのキャプションを結びつけるためのもの。
リンクについて
- aタグは基本的にアクセシビリティ機能が備わっているが、スタイルやJSで予期せぬ設定がされると逆にアクセシビリティを害する
- スタイル
- 既定では、下線, 色(未訪問/訪問済み), フォーカス時のリングがつく。
- 色だけでリンクとそれ以外のテキストを区別するのは良くない(既定では色+下線にしている)。視覚的に大きく区別する必要がある
-
onclick
イベント- aタグのhrefに
javascript:void(0)
とかをつけて、代わりにonclick
を指定してボタンっぽくすることがあるがこれはNG。リーダーにとっても良くないし、バグの温床にもなる
- aタグのhrefに
- 新しいタブが開いたり、外部アプリが開いたりする(e.g., tel)リンク
- 視覚障碍者や認知障碍者は、急にタブや別アプリが開くと混乱する可能性がある。下記のように、リンクの動作についての説明をリンクテキストに加えると良い
<a target="_blank" href="https://www.wikipedia.org/" >Wikipedia (opens in a new window)</a >
- アイコンボタンの場合は、aタグの中のimgタグにalt属性をつけ、そこに説明を書くと良い
- スキップリンク
- ページ冒頭のナビゲーションなどを飛ばして、メインコンテンツの開始位置までジャンプするためのページ内リンク
- これを実装しておくと、スイッチ制御、音声コマンドなどの支援技術を使う人にとって、簡単に本文までスキップできるので有益
- 近接性
- リンクをギチギチに詰めると運動障碍者が誤クリックを起こす可能性がある。marginを適切に取ること。
CSSとJavaScriptのアクセシビリティのベストプラクティス
CSS
- HTML要素を、予期される見た目と全然違う見た目にCSSでカスタマイズするな
- 例えばdivを見出しっぽくすると、スクリーンリーダーのユーザーが見出しを通じてページの見通しを得ることができない
- テキストは読みやすく。
- フォント、文字間隔、コントラスト
- 見出しが本文と区別できるように。リストはリストらしく。
- テキスト強調、略語
- em, strongタグなどで強調する場合、追加でスタイルをごちゃごちゃいじるとかえって混乱の元になる。太字、斜体で十分な時が多い
- abbrタグでの略語表記も同様
- リンク
- ポインタの挙動、フォーカス、未訪問/訪問済みなどの動作が、予期されたものと逸脱しないように
- フォーム
- これも、フォーカス時の挙動などが予期されたものと逸脱しないように
- テーブル
- 見出しを太字にしたり、ストライプ配色にしたりして見やすくすると良い
- コントラスト
- 色盲などの人でも読めるように
- WebAIMのColor Contrast Checkerを活用すると良い
- 物事をかくす
- デザインの要件上、特定の情報を隠しておき、ユーザーがみたい時に見られるようにしたいことがある(e.g., タブ切り替え)
- この時、
display: none
やvisibility: none
を使うと、スクリーンリーダーからコンテンツを隠してしまうので良くない。
- ユーザーがスタイルを変えることを受け入れる
- 視覚障碍者は、スタイルをブラウザ上で自分で上書きして、文字を大きくするかもしれない。そういったときでもサイトが機能するように柔軟にしておくとよい。
過度のJavaScriptに伴う問題
- HTML が JavaScript により生成され、CSS が JavaScript により生成される、みたいなものは、アクセシビリティやその他の問題が起こる可能性があり、お勧めできない
- キラキラの複雑なUIが必要なのか?プレーンなUIでいいのか?考える。JSは控えめに。ブラウザの組み込み機能を使う。
- JSの正しい使用例
- フォームバリデーション
- videoタグ用に、キーボードで操作できるカスタムコントロールを作る
- マウスに特有のイベント
- mouseoverにイベントリスナを仕掛けたりするのは、キーボード操作のユーザーにはアクセシブルでない。focusやblurは、デバイスによらずアクセシブル。
- clickイベントは、マウス特有に見えるがそうではない。フォーカスの当たってるリンク・フォーム要素でenterキーが押された時にも発火する。ただし、tabindexで、本来フォーカス可能でない要素がフォーカスを持つようにしている場合は工夫が必要。
WAI-ARIAの基本
WAI-ARIAとは
- WAI-ARIAが解決する課題
-
<nav>
や<footer>
などができる前は、divでそれらを表現する必要があった。 - 日付ピッカーは、ブラウザが提供してはいるが、スタイルを当てるのが難しいなどの理由で、divとJSで独自実装されることが多くある。
- 上記のような実装は、スクリーンリーダーは理解できない。
-
- WAI-ARIAの導入
- W3Cによって定められた、意味論追加・アクセシビリティ向上のための一連のHTML属性。
- 機能
- ロール(Role): 要素が何か、何をするかを定義する。(e.g.,
role="navigation"
,role="search"
,role="tablist"
) - プロパティ(Property): 要素の性質を定義する。(e.g.,
aira-required="true"
、arie-labelledby="<ラベルとなる要素のID>"
) - ステート(State): 要素の状態を定義する。(e.g.,
aria-disabled="true"
)
- ロール(Role): 要素が何か、何をするかを定義する。(e.g.,
- WAI-ARIA属性は、ブラウザのアクセシビリティAPI(=スクリーンリーダーが情報を取得する元)を除いて、サイトに影響を与えない。CSSの要素選択には使える。
- WAI-ARIAのサポート状況
- WAI-ARIAには大量の機能があり、検討が必要なOS、ブラウザ、スクリーンリーダーの組み合わせも大量にあるので、サポート状況を一元的に把握するのは難しい
- ブラウザはほぼ全てARIAの機能に対応している。スクリーンリーダーはそこまでではないが、ブラウザに近いものになってきている。
- いつWAI-ARIAを使うべきか
- 道しるべ/ランドマーク: navなど、HTMLの意味を再現するランドマークとしてふるまったり、tablistなどHTMLでは表現できない意味を表現したりする。
- 動的なコンテンツの更新:
aria-live
を使うことで、コンテンツの動的な更新時にユーザーにそれを伝えられる - キーボードのアクセシビリティ向上: tabindexなど
- 意味論的ではないコントロールのアクセシビリティ: divとCSS/JSでUIを作ってたりする場合、
role="button"
などでスクリーンリーダーの理解を助ける
- ただし、前提として、WAI-ARIAは必要な場合のみ使用する。使える時は、常にネイティブのHTML機能を使うべき。
WAI-ARIAの実装
道しるべ/ランドマーク
- header, nav, mainなど。VoiceOverのLandmarksメニューに、これらの要素が並ぶことにより、素早くアクセスできる
- また、例えば
role="search"
をメインの検索フォームにつけることで、検索フォームもlandmarksメニューに表示されるようになる (さらに、input要素にaria-label
属性をつけると、label要素なくてもスクリーンリーダーが説明を読んでくれる)
動的なコンテンツの更新
- 動的に書き換わるページ箇所をlive regionと呼ぶ。チャットルームなどでは、live regionの更新をユーザーに伝えることがクリティカル
-
aria-live
属性を更新される要素につけることで、スクリーンリーダがユーザーに更新を伝えることができる-
off
: 更新は通知されない(既定) -
polite
: ユーザーが暇になったときに更新通知 -
assertive
: 可能な限りはやくユーザーに更新通知
-
キーボードでのアクセシビリティの拡張
- 前述のtabindexを参照
意味論的ではないコントロールのアクセシビリティ
- フォームバリデーションとエラー警告
- エラーメッセージに、
role="alert"
をつけることで、適用先の要素がライブリージョンになり、変更を読み上げてくれるようになる。(window.alert
などのモーダルはアクセシビリティ的に問題がある)。また、リスト形式のエラーにaria-relavant="all"
をつけると、変更のたびに全てのエラーリストを読み上げてくれる - requiredなフィールドをスクリーンリーダーに理解させる
- 通常のUIに加え、
aria-required="true"
を付与
- 通常のUIに加え、
- max, minがあるフィールドをスクリーンリーダーに理解させる
-
aria-valuemin
とかは一応あるが、それほどサポートされていない。 - それよりは、placeholderに入れた方が、読み上げてくれる
-
- すべての入力にlabelをつける
-
aria-label
やaria-labelledby
でも良い
-
- disabledなフィールド
- 普通に
disabled
をつけると、スクリーンリーダーはそれをスキップしてしまう。aria-disabled="true"
ならスキップせず読み上げてくれる
- 普通に
- エラーメッセージに、
- ボタン
- divでどうしてもボタン作りたい場合。
-
role="button"
を指定すると、スクリーンリーダーが読み上げてくれる。 - ただ、これだけだとタブ移動やenterでクリックさせることはできないので、tabindexなどの対応もやらないといけない。ベストなのはbutton要素を使うこと。
- その他、意味論的なHTMLだと表現が難しいUI
- combobox、slider、tabpanel、treeなど。これらを
role
属性に指定することで、スクリーンリーダーに理解させることができる。roleの他にも、aria-selected
、aria-hidden
(読み上げられないようにする)などを指定してUIの細かい部分を詳細に説明できる。
- combobox、slider、tabpanel、treeなど。これらを
アクセシブルマルチメディア
シンプルな画像
- 前述の方法で代替テキストを用意する
オーディオとビデオコントロール
- audioとvideoタグをHTMLに入れれば、何もしなくても再生・停止・シークなどのコントロールが得られる。
- ただし、このビルトインコントロールはいくつか問題がある
- キーボードでアクセスできない
- スタイルをいじれない
- video、audio要素はHTMLMediaElementインターフェースを実装している。そのため、これらの要素には
pause()
やplay()
といったメソッドがあり、これをJSで操作することでカスタムできる。
オーディオトランスクリプト
- 聴覚障碍者にオーディオコンテンツを提供する場合、文字起こしが必須。商用サービス、AI、自分でつけるなど、いろいろな方法で文字起こしできる。
ビデオテキストトラック
- 聴覚、視覚障碍者、非母語話者のため、ビデオにテキストトラックを含める必要がある
- テキストトラックには、キャプション(話されている言葉、感情、音楽など)、字幕、ディスクリプション(どのようなシーンに見えるか)、チャプタータイトル などがある
- HTMLのvideo要素にテキストトラックを追加するには、WebVTTというフォーマットでテキストを書いて
.vtt
ファイルとして保存する。その後、<track>
要素で作ったファイルを読み込む。
その他
- canvas、Flash、Silverlightなど。100%アクセシブルにできるとは限らないが、ケースバイケースで対応する。
モバイルのアクセシビリティ
- 最近のモバイルデバイスでは、一般的なアクセシビリティのベストプラクティスに沿っていれば大体OK。
- 以下に気を付ける
- タッチスクリーン操作でアクセシブルか
- ユーザー入力が苦痛でないか(e.g., タイピングを最小限に)
- レスポンシブデザイン
- AndroidではTalkBack、iOSではVoiceOverというスクリーンリーダーが使える。
- タッチスクリーン操作
- 前述のようにonclickはOKだが、onmousedownなどは問題。使いたい時は、ontouchstartなどを一緒に設定すると良い
- ユーザー入力
- モバイルではテキスト入力が面倒。selectメニューを活用したりすると良い。
- また、inputタグで
type
属性をdate、time、number、tel、emailなどと指定すると、適切なキーボードを表示してくれたりと便利なため利用を検討すると良い
- レスポンシブデザイン
- メディアクエリ、flexなどを活用
- レスポンシブ画像により帯域を節約
- その他
- ズームを無効にしない: viewportを使うとzoom無効にできるが、ズームしたいユーザーもいるためやらないこと。
- メニューにアクセスしやすく: ハンバーガーメニューがタッチでちゃんと開くこと、操作中は他の要素が邪魔にならないことを確認