失敗例で学ぶアクセシビリティ(WCAG 2.1)

2022/09/25

はじめに

突然アクセシビリティ筋を鍛えたくなったのが先月の話です.

WCAG 2.1の日本語訳を全部読めばムキムキになれるのではと思い,先頭から読み進めて1ヶ月かかり読了しました.

中でも面白かったのは「失敗例」という項目です.ここには良くないWebページの実装例がたくさん書かれており,「あ〜初心者ならやりがちだよね〜」という例から「え…?職場のコードでやらかしてるんだが……?」みたいな例まであり,マジで死にたくなりました.

私の学習メモとして,またはアクセシビリティの入門資料として,あるいは過去の過ちへのみそぎとして,やらかしそうな失敗例を, WCAG 2.1のすべての達成基準に対して 思いつく限りまとめようと思います.

レベル(A,AA,AAA)の低い順に記載しますので,下に行くほど発展的な内容になります.

失敗に気づいたら

「WCAG2.1 達成基準の番号 十分な達成方法」でググり,達成方法に関する公式の説明を見つけます.

例えば基準1.1.1なら以下の部分です.

十分な達成方法 - 達成基準 1.1.1: 非テキストコンテンツを理解する

予防線

この記事では簡単さを優先しています.用語や説明を言い換えたり,まとめたり,割愛したりしています.

入門資料には使えますが,厳格な適合評価などには使えません.

凡例

成功例 ここに成功例が書かれます

失敗例 ここに失敗例が書かれます

レベルA

クリアすることで最低限のアクセシビリティが実現されるレベル

1. 知覚可能(A)

ユーザーがコンテンツを知覚(見る,聞く,触る…)できること

1.1 テキストによる代替(A)

テキストによる代替があること

1.1.1 非テキストコンテンツ

成功例 非テキストコンテンツ(写真,イラスト,グラフ,アスキーアートなど)に,適切な代替がある

失敗例 代替がない

<p>以下は売上を表したグラフである</p>

<img src="graph.jpg" />

→目の見えない人には伝わらない

失敗例 代替が不適切

<p>以下は売上を表したグラフである</p>

<img src="graph.jpg" alt="売上の推移.オレンジ色は今年度の売上を表す" />

ここでgraph.jpgは以下の画像

graph.jpgの表示例.棒グラフの画像.グラフは増加を示している.一番右の棒だけオレンジ色で他の棒は緑色

→やはり伝わらない.売上は増加?減少?オレンジ色ってどこ?

失敗例 装飾画像に代替がある

<!-- info_icon.gifは「i」を丸で囲ったようなアイコン -->
<a><img src="info_icon.gif" alt="インフォアイコン" />ヘルプ</a>

→「インフォアイコン」って読み上げられても…

<!-- spacer.pngは余白を調整するためだけの透明な画像 -->
<img src="spacer.png" alt="スペーサー" />

→「スペーサー」って読み上げられても…

失敗例 装飾画像にalt属性がない

<img src="spacer.png" />

→支援技術が画像に反応してしまう

例えばスクリーンリーダーが「ラベルのない画像」と読み上げる

正しくはalt=""

失敗例 CSSで重要な画像を表示している

<p>以下は歴史的に有名な写真です</p>

<span></span>

<style>
  span {
    background-image: url(image.jpg);
  }
</style>

失敗例 テキストだけどテキストじゃないものに代替がない

<p>ネ申</p>

<pre>
 ____ ∧ ∧
|\ /(´~`)\
| | ̄ ̄ ̄ ̄ ̄|
| |=みかん=|
 \|_____|
</pre>

1.2 時間依存メディア(A)

ここでは以下の3つの基準をまとめて扱う.

  • 1.2.1 音声のみ及び映像のみ(収録済)
  • 1.2.2 キャプション(収録済)
  • 1.2.3 音声解説、又はメディアに対する代替(収録済)

これらの基準では,収録済みの音声や映像について次のような代替を求める

成功例 音声ファイル(mp3など)に対する代替(書き起こしなど)がある

成功例 動画の音声トラックに対するキャプションがある

成功例 動画の映像トラックに対する音声解説または代替(書き起こしなど)がある

失敗例 動画の音声トラックに対するキャプションがない

<video src="gag.mp4">一発ギャグ大会の動画記録</video>
<!-- この動画にはキャプションや書き起こしがない -->

→耳の聞こえない人には伝わらない

失敗例 音声のキャプションや代替が不十分

<video src="gag.mp4">一発ギャグ大会の動画記録</video>
<!-- この動画には埋め込みのキャプション(オープンキャプション)がある -->
<!-- キャプション:サバンナ八木「ブラジルの人聞こえますかー!!!」 -->

→会場の反応(「笑い声が起こった」など)も書くべきである

このキャプションでは,ギャグがウケたのか滑ったのかわからない.したがって,音声を代替しきれていない

失敗例 映像に対する音声解説や代替がない

<video src="gag.mp4">一発ギャグ大会の動画記録</video>
<!-- この動画には音声解説がない -->

→目の見えない人には伝わらない

失敗例 映像の音声解説や代替が不十分

<video src="gag.mp4">一発ギャグ大会の動画記録</video>
<!-- この動画には音声解説が付属している -->

<!-- 音声解説:次の発表者であるサバンナ八木氏がステージに登場し,叫んだ -->
<!-- 動画音声:ブラジルの人聞こえますかー!!! -->

→地面に向かって叫んだことを説明していない

そのため,映像を代替しきれていない

1.3 適応可能(A)

様々な閲覧方法にコンテンツが適応できること.例えばスクリーンリーダーが読み上げる場合,CSSを無効化した場合など

1.3.1 情報及び関係性

成功例 情報,構造,関係性はプログラムによる解釈が可能

失敗例 見た目,装飾のために間違った要素を使う

<p>新商品を開発しました</p>

<h2>好評発売中!</h2>

→文字を大きくするために見出しを使っている

<blockquote>定理:三角形の内角の和は180度になる</blockquote>

→字下げと強調のために引用を使っている

<fieldset>
  <legend>今日の天気</legend>
  <p>雷雨です</p>
</fieldset>

→枠線のためにfieldsetを使っている

カレーの作り方を説明します.<br />
<br />
まずスーパーに行きます.<br />

→改行のみで段落を表している

カレーの作り方を説明します.
<p></p>
まずスーパーに行きます.

→段落をスペーサーとして使っている

失敗例 CSSで非装飾のコンテンツを提供している

<p>Vimは<span class="strong">最高のエディタです!</span></p>

<style>
  .strong {
    font-weight: bold;
  }
</style>

→CSSを無効にしたとき意味が伝わらなくなる

<style>
  .good:before {
    content: "良いこと:";
  }
  .bad:before {
    content: "悪いこと:";
  }
</style>

<p class="good">ごはんをカレーと食べる</p>

<p class="bad">ごはんをシチューと食べる</p>

→CSSを無効にしたとき意味が伝わらなくなる

つまり,CSSを装飾以外に使っているため失敗

失敗例 リンクをエミュレートしている

<img
  src="download_button.png"
  alt="ダウンロードページへ"
  onclick="location.href='download.html'"
/>

→普通にaタグを使おう

1.3.2 意味のある順序

成功例 コンテンツが正しい順序で解釈される

失敗例 CSSでコンテンツの順序を変えている

例:以下はカレーのランディングページである

カレールーのランディングページ.画面左上に「カレーを」,中央に「食べられる」,右下に「幸せ」と書かれている

これは次のようなHTMLで書かれている

<div class="container">
  <span>食べられる</span>
  <span class="top-left">カレーを</span>
  <span class="bottom-right">幸せ</span>
</div>

<style>
  /* 省略 */
</style>
すべてのコード
<div class="container">
  <span>食べられる</span>
  <span class="top-left">カレーを</span>
  <span class="bottom-right">幸せ</span>
</div>

<style>
  .container {
    position: relative;
    width: 300px;
    height: 100px;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .top-left {
    position: absolute;
    top: 0;
    left: 0;
  }
  .bottom-right {
    position: absolute;
    bottom: 0;
    right: 0;
  }
</style>

→CSSを無効化すると「食べられるカレーを幸せ」となり,意味がわからなくなる

失敗例 テーブルレイアウトを使用している

例:以下は俳句の表示例である

俳句の表示例.左から縦書きで「古池や<改行>蛙飛びこむ<改行>水の音」

これは次のようなHTMLで書かれている.

<table>
  <tr>
    <td>水の音</td>
    <td>蛙飛びこむ</td>
    <td>古池や</td>
  </tr>
</table>

<style>
  td {
    width: 1em;
  }
</style>

→CSSを無効化すると「水の音蛙飛びこむ古池や」となってしまう

失敗例 文字間隔の調整にスペースを使用している

<p>日本の地名</p>

<!-- 横幅を名古屋に合わせるため全角スペースを使用している -->
<ul>
  <li>東 京</li>
  <li>大 阪</li>
  <li>名古屋</li>
</ul>

→スペースによって「とうきょう」が「ひがし,きょう」などと読まれてしまう

1.3.3 感覚的な特徴

成功例 コンテンツの説明が,構成要素の感覚的特徴(形,色,大きさ,位置,音など)だけに依存しない

失敗例 コンテンツの説明が,構成要素の感覚的特徴だけに依存している

<p>赤いラベルは必須項目を表します</p>

<label for="name" style="color: red">氏名</label>
<input name="name" id="name" />

→目の見えない人には伝わらない

赤ってどこ?

<p>ダウンロードは画面右下のリンクから!</p>

→目の見えない人には伝わらない

右下にどのリンクが表示されてるの?

<!-- 簡単なクイズのページ -->
<!-- playは効果音を鳴らす独自のJavaScript関数 -->
<p>クイズ:どちらが美味しいお菓子でしょうか?</p>

<button onclick="play('正解音.mp3')">たけのこの里</button>

<button onclick="play('不正解音.mp3')">きのこの山</button>

→耳の聞こえない人にはどちらが正解かわからない

1.4 判別可能(A)

コンテンツを見やすく,聞きやすいものにすること.

1.4.1 色の使用

成功例 色が情報を伝えるための唯一の手段になっていない

また,本基準では以下も認めている.

成功例 色がリンクやコントロールを特定する唯一の手段だが,周囲のテキストと3:1以上のコントラスト比があり,フォーカス時に追加の視覚的手がかりがある

しかし,基本的には色以外にも情報伝達の手段を用意するのがベストプラクティスと思われる.

失敗例 色が情報を伝えるための唯一の手段になっている

<img src="image.png" alt="姉妹の写真.うすい赤髪が姉,うすい青髪が妹" />

→髪の色を見分けられない利用者がいるかもしれない

特に年配,ロービジョン,色覚異常の利用者

失敗例 リンクが他と見分けづらい

詳細は<a href="help.html">ヘルプ</a>を参照してください

<style>
  body {
    color: #000;
  }

  a {
    text-decoration: none;
    color: #575757;
  }
</style>

これは次のように表示される

周囲と似た色のリンクの例.「ヘルプ」の部分がリンク.周囲は#000000,リンクは#575757の色

→リンクを見分けられない利用者がいるかもしれない

この場合のコントラスト比は2.9:1である.これは,達成基準の3:1を下回っているため失敗となる

1.4.2 音声の制御

成功例 自動再生され3秒以上長く続く音声を一時停止・停止・音量調整できる機構がある

失敗例 音声が邪魔

<p>このページでは爆音ノリノリBGMが無限ループ再生されます!ノッていこうぜ!</p>

<audio src="bgm.mp3" autoplay loop></audio>
<!-- 注:コントロールはない -->

→スクリーンリーダーの読み上げが聞こえねぇよタコ

最近は自動再生しないブラウザも多い

2. 操作可能(A)

UIコンポーネント(ボタンやテキストボックスなど)とナビゲーションは操作可能でなければならない

2.1 キーボード操作可能(A)

キーボードで操作できること

2.1.1 キーボード

成功例 コンテンツのすべての機能はキーボードで操作できる

成功例 ただし,その機能が軌跡に依存している場合はのぞく

軌跡に依存する機能の例:ある保険の契約サイトでは,手書きのサインを画面に書く

署名は,その軌跡自体に意味があるため例外となる.一方で,単なる手書き文字入力機能の場合は例外にならない.その場合は追加のテキストボックスを設置すれば良い.

失敗例 不完全なエミュレートを行っている

例:以下では,img要素でボタンをエミュレートしている.マウスでは使用できる

<img onclick="alert('hello')" src="hello_button.png" alt="say hello" />

→しかしキーボードで操作できない

キーボードで操作するためには,フォーカス可能にする必要がある

失敗例 フォーカスを強制的に解除している

<!-- ボタンに謎の枠線が表示されないように,this.blurを使ってみた -->
<button type="button" onclick="alert('hello')" onfocus="this.blur()">
  say hello
</button>

→ボタンにフォーカスできないためキーボードで操作不能

失敗例 UIコンポーネントにdisplay: none;を使用している

<!-- カスタムのボタン -->
<label>
  <!-- 実際のボタンはdisplay: noneで隠してしまって… -->
  <input type="button" style="display: none" onclick="alert('hello')" />

  <!-- こちらの要素を表示する.spanなのでスタイルを当てやすいぞ! -->
  <span>say hello</span>
</label>

→実際のボタンをdisplay: none;しているのでキーボードで操作できない.支援技術も反応しない.

UIコンポーネントを独自に実装しようとした場合の失敗例は4.1.2 名前(name)・役割(role)及び値(value)も参照

2.1.2 キーボードトラップなし

成功例 UIコンポーネントがフォーカスを受け取ったあと,キーボードだけでフォーカスを外せる

失敗例 フォーカスを離さないUIコンポーネント

例:このテキストボックスはなにか値を入力するまでフォーカスを離さない

<label>
  名前(必須)
  <input />
</label>

<script>
  const input = document.querySelector("input");
  input.addEventListener("keydown", (e) => {
    if (e.key === "Tab" && input.value === "") {
      input.focus();
      e.preventDefault();
    }
  });
</script>

→そのことを知らないキーボード利用者はここから抜け出せなくなり,困惑する.

失敗例 フォーカスを捕まえるFlash,アプレットコンテンツ

→最近はあまりない

2.1.4 文字キーのショートカット

成功例 単純な(文字,句読点,記号のみの)キーボードショートカットが無い

成功例 単純なショートカットがある場合:ショートカットを解除できる,または再割当てできる,またはフォーカス時のみ限定的に有効である

失敗例 単純なショートカット

例:あるメール管理画面では,次のショートカットが利用可能である

  • d: メールを削除する(delete)
  • y: ダイアログにイエスで答える(yes)

シナリオ:アリスは障害のため音声入力を利用している.メール管理画面の閲覧中に,同僚のデイジーがやってきた.アリスは「ハイ,デイジー」と言った.

ここで音声入力が作動し「Hi, D ais y 」と入力された.これにより

  1. 「D」によってメールの削除が反応した
  2. 「本当に削除しますか?」のダイアログが出たが「y」によって削除が実行されてしまった

2.2 十分な時間(A)

コンテンツを読み,使用する十分な時間があること

2.2.1 タイミング調整可能

成功例 コンテンツに制限時間がない

成功例 制限時間がある場合,次のいずれかである

  • 制限時間を解除できる
  • 時間を10倍に変更できる
  • 少なくとも20秒の猶予をもって時間を10倍以上に延長できる
  • リアルタイムのイベント(例:オークション)
  • 制限時間が必要不可欠
  • 制限時間が20時間より長い

失敗例 コンテンツに短い時間制限がある

例:あるサイトは移転済みのページに対して以下のようなコンテンツを返す

<head>
  <title>これは古いページです</title>
  <meta http-equiv="refresh" content="5; url=http://www.example.com/newpage" />
</head>
<body>
  <p>
    このページは古く,新しいドメインに移転しました..5秒後にリダイレクトします.
  </p>
</body>

→スクリーンリーダー「これは古いページです.このページは古く,新しいドメインに(リダイレクトにより読み上げ中断)」

→ユーザー「???(困惑)」

失敗例 一定時間でページを再読込している

<!-- ある古のチャットサイトは,一定時間で自分自身を再読込する -->
<head>
  <title>チャット</title>
  <meta http-equiv="refresh" content="5; url=http://www.example.com/chat" />
</head>
<body>
  <h1>メッセージ一覧</h1></body>

→スクリーンリーダー「チャット,メッセージ一覧.チャット,メッセージ一覧.チャット,メッセージ一覧……」

2.2.2 一時停止、停止、非表示

成功例 自動で動く,または点滅するコンテンツがない

成功例 自動で動く,または点滅するが,次のいずれかである

  • 5秒以内に止まる
  • 停止する,または非表示にする機能がある
  • 単独で提示される
  • 必要不可欠

失敗例 動く必要のないコンテンツが動いている

<!-- 目立たせるために点滅させる -->
<blink>セール実施中!</blink>

<h2>過去の商品</h2>
<!-- 証券取引所にならって,横スクロールで株価を表示する -->
<marquee>最新の株価情報:今日の株価は…</marquee>

<h2>その他の情報</h2>

→とめるべき

注意欠陥障害をもつユーザーは,動くコンテンツを追うのがストレス.また,それらに気を取られると,動いていないコンテンツも読みづらくなる

2.3 発作と身体的反応(A)

発作を起こすようなコンテンツは作成しないこと

2.3.1 3 回の閃光、又は閾値以下

成功例 どの1秒間にも3回の閃光を放つものがない

成功例 1秒間に3回の閃光を放つが,その面積が21,824平方ピクセルよりも小さい(一般的な画面サイズと距離の場合)

失敗例 基準を上回る閃光がある

例:ある広告はユーザーの注意を引くために,大きな面積で素早く点滅する

→点滅をやめるべき

光過敏性発作に関するガイドラインは,Webだけでなくゲーム業界,テレビ業界でも規定されている

2.4 ナビゲーション可能(A)

利用者がサイト内で迷わないこと

2.4.1 ブロックスキップ

成功例 ヘッダーブロックをスキップする方法がある

失敗例 ヘッダーブロックをスキップできない

<body>
  <ul>
    <li><a>ナビゲーションリンク1</a></li>
    <li><a>ナビゲーションリンク2</a></li>
    <li><a>ナビゲーションリンク3</a></li></ul>

  <div>広告1</div>
  <div>広告2</div>
  <div>広告3</div><span>重要情報:明日メンテナンスを行います</span>

  <p>それでは本題ですが…</p>
</body>

→本文まで長い

目のみえる人は,ヘッダーや広告を無視してページの全体像を把握できる.しかし,そうでない人にとっては難しい

例えば,本文直前にh1見出しを置く,本文をmain要素でかこむ,ヘッダーブロックのスキップリンクを設置すると良い

2.4.2 ページタイトル

成功例 わかりやすいページタイトルがついている

失敗例 ページタイトルがデフォルトのまま

<head>
  <title>無題のドキュメント</title>
</head>

→なんのページ?

失敗例 ページのタイトルが不明瞭

例:スミスさんはABC銀行のオンラインバンキングを利用している

<head>
  <title>口座情報</title>
</head>

→どの銀行かわからない.スミスさんは他の銀行にも口座をもっている

<head>
  <title>口座情報 | ABC銀行</title>
</head>

→どの口座かわからない.スミスさんはABC銀行に複数の口座をもっている

<head>
  <title>口座番号 123-4567 の情報 | ABC銀行</title>
</head>

→「情報」は少し曖昧かもしれない.もしさらにタイトルを限定できるなら,「残高」や「直近の取引」のほうが良いかもしれない

2.4.3 フォーカス順序

成功例 フォーカス順序が意味および操作性を損なわない

失敗例 DOMの順序が見た目と一致していない

例:以下は市のページ.上部に重要な情報が書かれている

市のページのスクリーンショット.上部に「緊急情報!地球が爆発します!詳細はこちら」と書かれており,その後「市のページ」「ゴミの出し方」「市長の日記」「よくある質問」と続く

これは次のようなHTMLで書かれている

<h1>市のページ</h1>
<h2>ゴミの出し方</h2><h2>市長の日記</h2><h2>よくある質問</h2><strong class="emergency">
  緊急情報!!!地球が爆発します!
  <a href="http://example.com/emergency">詳細はこちら</a>
</strong>

<style>
  body {
    padding: 50px 10px;
  }

  .emergency {
    position: absolute;
    top: 0;
    left: 0;
    padding: 0.5em;
    color: yellow;
    background: black;
  }
  .emergency a {
    color: red;
  }
</style>

→目が見えてキーボードを使っている利用者は困惑する.ページ上部にあるのに,フォーカスを移動させるには「ゴミの出し方」「市長の日記」「よくある質問」などを通過しなければならない

→目の見えない利用者は,重要な情報を最後に見つけることになる.

失敗例 モーダルダイアログにフォーカスが移動しない,フォーカストラップがない

例:以下のようなモーダルダイアログの実装がある

<button onclick="document.querySelector('.dialog').style.visibility='visible'">
  ダイアログを開く
</button>

<div class="dialog">
  <div>
    <p>これはモーダルダイアログです</p>
    <button
      onclick="document.querySelector('.dialog').style.visibility='hidden'"
    >
      閉じる
    </button>
  </div>
</div>

<button>他のボタン</button>

<style>
  /* 省略*/
</style>
すべてのコード
<button onclick="document.querySelector('.dialog').style.visibility='visible'">
  ダイアログを開く
</button>

<div class="dialog">
  <div>
    <p>これはモーダルダイアログです</p>
    <button
      onclick="document.querySelector('.dialog').style.visibility='hidden'"
    >
      閉じる
    </button>
  </div>
</div>

<button>他のボタン</button>

<style>
  .dialog {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh;
    background-color: #0009;
    display: flex;
    justify-content: center;
    align-items: center;
    visibility: hidden;
  }
  .dialog div {
    padding: 1em;
    background: white;
  }
</style>

ここで,以下の操作をしたとする

  1. Tabキーで「ダイアログを開く」にフォーカスを当て,Space キーでボタンを押した
  2. しかし,フォーカスは「ダイアログを開く」のままである.
  3. ダイアログの暗い背景でフォーカスインジケーターが見えず,利用者は自身の位置を見失ってしまった

現状のスクリーンショット.モーダルが表示され,背後の「ダイアログを開く」ボタンにフォーカスがあたっている

→モーダルダイアログを開いたときに,ダイアログ内にフォーカスが移るべきだった

続けて,以下の操作をしたとする

  1. 利用者は,なんとか苦労して「閉じる」ボタンにフォーカスを当てた
  2. しかし,誤ってもう一度Tabキーを押してしまった.
  3. フォーカスは「他のボタン」に移ってしまい,また自身の位置を見失った

現状のスクリーンショット.モーダルが表示され,背後の「他のボタン」にフォーカスがあたっている

→モーダルダイアログにフォーカストラップがあるべきだった

失敗例 モードレスダイアログがDOM的に遠くにある

例:以下のようなモードレスダイアログの実装がある

<button onclick="document.querySelector('.dialog').style.visibility='visible'">
  ダイアログを開く
</button>
<button>他のボタン1</button>
<button>他のボタン2</button>
<button>他のボタン3</button>

<div class="dialog">
  <div>
    <p>これはモードレスダイアログです</p>
    <button
      onclick="document.querySelector('.dialog').style.visibility='hidden'"
    >
      閉じる
    </button>
  </div>
</div>

<style>
  /* 省略 */
</style>
すべてのコード
<button onclick="document.querySelector('.dialog').style.visibility='visible'">
  ダイアログを開く
</button>
<button>他のボタン1</button>
<button>他のボタン2</button>
<button>他のボタン3</button>

<div class="dialog">
  <div>
    <p>これはモードレスダイアログです</p>
    <button
      onclick="document.querySelector('.dialog').style.visibility='hidden'"
    >
      閉じる
    </button>
  </div>
</div>

<style>
  .dialog {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    visibility: hidden;
  }
  .dialog div {
    padding: 1em;
    border: 3px solid black;
  }
</style>

ここで,以下の操作をしたとする

  1. Tabキーで「ダイアログを開く」にフォーカスを当て,Space キーでボタンを押した
  2. ダイアログが開いた.利用者はダイアログを消したいと考えた
  3. 「閉じる」ボタンを操作するためにTabキーを押したが,フォーカスは「他のボタン1」に移った
  4. 同様に「他のボタン2」「他のボタン3」を経由して,やっと「閉じる」ボタンにたどり着いた

→モードレスダイアログは,トリガーの近くに配置すべきである

最近では,自身でダイアログを実装するのではなく,dialog要素の使用を検討してもいいかもしれない.dialogの仕様ではフォーカス管理も考慮されている.

2.4.4 リンクの目的(コンテキスト内)

成功例 リンクのテキスト単独で,その目的が判断できる

成功例 リンクのテキストとコンテキストから,その目的が判断できる

失敗例 リンクテキストとコンテキストから目的がわからない

<h1>日記一覧</h1>

<p>2022/09/24:今日はプログラミングの勉強をしました.具体的には…</p>

<p><a>続きを読む</a></p>

→日記のプレビューとリンクを同じ段落にすべき

利用者は「続きを読む」が何の続きを読むリンクなのかわからない

2.5 入力モダリティ(A)

様々な入力機器で操作しやすいこと

2.5.1 ポインタのジェスチャ

成功例 マルチポイントで操作する機能は,シングルポインタでも操作できる

成功例 軌跡ベースのジェスチャで操作する機能は,シングルポインタでも操作できる

失敗例 マルチポイントでしか操作できない機能がある

例:ある地図アプリでは,ピンチイン / アウトでしか地図を拡大 / 縮小できない.

→以下のような人には利用できない

  • マルチポイント環境だが障害によりジェスチャを遂行できない
  • マルチポイント環境ではない
    • マウス
    • ヘッドポインタ
    • 視線システム
    • 音声制御マウスエミュレーター

拡大・縮小ボタンを配置すべき

失敗例 軌跡ベースのジェスチャでしか操作できない機能がある

例:Web上で動く迷路ゲームは,ドラッグ操作でのみ自機を操作できる

→ジェスチャを遂行できない人には利用できない

例えば自機を操作できる「上」「下」「左」「右」のボタンを配置する

2.5.2 ポインタのキャンセル

成功例 シングルポインタでの操作は,キャンセル可能である

失敗例 ダウンイベントで機能を実行している

<button onmousedown="alert('削除しました')">アカウントを削除します</button>

→意図せずボタンを押し込んでしまった場合,アカウントが削除されてしまう

onclickを使用していれば,ボタンを押し込んだままポインタを外すことでキャンセルできた

2.5.3 名前(name)のラベル

成功例 UIコンポーネントのラベルが名前(アクセシブルな名前)に含まれる

失敗例 UIコンポーネントのラベルが名前に含まれていない

発送先:<input />

inputには何の名前もついていない

発送先:<input name="発送先" />

→やはりinputには何の名前もついていない

アクセシブルな名前とname属性を混同している

<label>発送先:</label><input />

→やはりinputには何の名前もついていない

label要素を使用しているがinputと関連がない

発送先:<input title="所在地" />

→ラベルと名前がずれている.以下のようなシナリオが考えられる

  1. スクリーンリーダー「発送先」
  2. 目の見えないユーザー「発送先を入力するるんだな.(Tabキーを押下)」
  3. スクリーンリーダー「テキストボックス,所在地」
  4. ユーザー「あれ?発送先じゃなかったの?発送先と所在地って一緒の意味なのか……?」

または

  1. 音声入力ユーザー「(画面を見て)お,発送先を入力するんだな.『発送先テキストボックスに,フォーカス』」
  2. 支援技術「『発送先テキストボックス』は見つかりません」
  3. ユーザー「???」
2.5.4 動きによる起動

成功例 デバイスや利用者の動きで操作できる機能は,UIコンポーネントでも操作できる

成功例 デバイスや利用者の動きで操作できる機能は,動きへの反応を無効化できる

失敗例 動きでのみ操作できる機能がある

例:あるスマートフォン向けシューティングゲームサイトは,端末を傾けることで自機を操作する.それ以外に操作方法はない

例:あるスマートフォン向けSNSサイトは,同時に2つの端末を振ることでアカウントを相互フォローできる.それ以外にフォローの方法はない

→以下の利用者がサイトを使えない

  • 端末にセンサーが搭載されていない
  • 運動障害があり,動きを遂行できない
  • 端末が机やベッドに固定されている

同等の機能を提供するボタンなどを設置するべき

失敗例 動きに対する反応を無効化できない

例:あるスマートフォン向け地図サイトは,地磁気センサによって地図が自動回転する.しかしそれを止められない

→センサに問題がある場合,またはスマートフォンを立てて持った場合などに地図が見づらい

3. 理解可能(A)

理解しやすいコンテンツを作ること

3.1 読みやすさ(A)

読みやすいコンテンツを作ること

3.1.1 ページの言語

成功例 ウェブページの自然言語がどの言語か解釈可能である

失敗例 ウェブページの自然言語がどの言語か解釈可能でない

<!DOCTYPE html>
<html>
  <head>
    <title>お好み焼きはご飯のおかずとなるか</title>
  </head>
  <body>
    <p>ならない</p>
  </body>
</html>

→言語の指定がない

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>コロッケはご飯のおかずとなるか</title>
  </head>
  <body>
    <p>なる</p>
  </body>
</html>

→言語の指定が間違っている

スクリーンリーダーは誤った音声エンジンで読み上げてしまうかもしれない

3.2 予測可能(A)

コンテンツの挙動が予測可能であること

3.2.1 フォーカス時

成功例 UIコンポーネントがフォーカスを受け取ったとき,コンテキストの変化を引き起こさない

失敗例 UIコンポーネントがフォーカスを受け取ったとき,コンテキストの変化を引き起こす

例:あるフォームでは,ヘルプボタンがフォーカスを受け取ったときにダイアログを表示する

氏名と住所を尋ねるフォームのスクリーンショット.氏名のテキストボックスとそのヘルプボタン.住所のテキストボックスとそのヘルプボタンがある

コードを見る
<div>
  <label>氏名:<input /></label>
  <button data-help="氏名とは,名前のことです">ヘルプ</button>
</div>
<div>
  <label>住所:<input /></label>
  <button data-help="住所とは,あなたが住んでいる場所のことです">ヘルプ</button>
</div>

<dialog>
  <form method="dialog">
    <p></p>
    <button>閉じる</button>
  </form>
</dialog>

<script>
  // ヘルプボタンにフォーカスが移ったらメッセージを表示する
  let last;
  for (const button of document.querySelectorAll("button[data-help]")) {
    button.addEventListener("focus", (e) => {
      if (last === e.target) return;
      last = e.target;

      document.querySelector("dialog p").textContent = e.target.dataset.help;
      document.querySelector("dialog").showModal();
    });
  }
</script>

→キーボードで操作すると,すべてのヘルプメッセージを見ることになり煩雑

例えば,クリックでメッセージを表示するようにする

3.2.2 入力時

成功例 UIコンポーネントの設定を変更しても,コンテキストが予期せず変化しない

失敗例 UIコンポーネントの設定を変更すると,コンテキストが予期せず変化する

例:自動送信

一番優れているエディタを訪ねるフォームのスクリーンショット.Vim,Emacs,VSCodeの選択肢がある

<form action="#">
  <!-- 省略 -->
</form>

<script>
  // 選択肢を選んだときに自動送信
  // 送信ボタンを押さなくていいからラクだよね
  for (const input of document.querySelectorAll("input")) {
    input.addEventListener("change", () =>
      document.querySelector("form").submit()
    );
  }
</script>
すべてのコード
<form action="#">
  <fieldset>
    <legend>一番優れているエディタを選択してください</legend>

    <div>
      <input type="radio" name="editor" id="vim" value="vim" />
      <label for="vim">Vim</label>
    </div>
    <div>
      <input type="radio" name="editor" id="emacs" value="emacs" />
      <label for="emacs">Emacs</label>
    </div>
    <div>
      <input type="radio" name="editor" id="vscode" value="vscode" />
      <label for="vscode">Visual Studio Code</label>
    </div>
  </fieldset>
</form>

<script>
  // 選択肢を選んだときに自動送信
  // 送信ボタンを押さなくていいからラクだよね
  for (const input of document.querySelectorAll("input")) {
    input.addEventListener("change", () =>
      document.querySelector("form").submit()
    );
  }
</script>

→項目を選択しただけなのにフォームが送信されてしまう

間違った選択肢を選んでも訂正できない

3.3 入力支援(A)

間違いを防ぎ,修正を支援すること

3.3.1 エラーの特定

成功例 エラーが検出されたときは,その箇所が特定され,エラー内容がテキストで説明される

失敗例 エラーが検出されたが,その内容の提示が不適切

例1:ある登録フォームを送信したが,次のようなページが返ってきたとする

<form action="#">
  <label>名前:<input /></label>
  <label>メールアドレス:<input /></label>

  <p style="color: red">エラーがあります</p>
  <button>送信</button>
</form>

→目の見えないユーザーは,そもそもエラーに気づかないかもしれない

「送信したのに同じページが返ってきたぞ」と思い,読み進めて初めてエラーがあったことに気づく

例2:例1を改良して,エラーに気づきやすくした

<head>
  <title>エラーあり | 登録フォーム</title>
</head>
<body>
  <form action="#">
    <p style="color: red" tabindex="-1">エラーがあります</p>
    <label>名前:<input /></label>
    <label>メールアドレス:<input /></label>
    <button>送信</button>
  </form>

  <script>
    document.querySelector("p").focus();
  </script>
</body>

→エラーに気づけるようにはなった

しかし,どの項目がどんなエラーなのかわからないため修正できない

3.3.2 ラベル又は説明

成功例 利用者の入力を要求する場合は,ラベルまたは説明文がある

失敗例 ラベルまたは説明文がない

電話番号のフォーム例.3つのテキストボックスがハイフンでつながっている

電話番号を入力:<input /> - <input /> - <input />

<style>
  input {
    width: 4em;
  }
</style>

→各inputに説明文がない.

→各inputのラベルはそれぞれ「電話番号を入力:」「-」「-」だが,意味がわからない

見た目上は典型的な電話番号のフォーマットを要求しているが,目の見えない人には分かりづらい

4. 堅牢(A)

様々なUAが解釈できるように,堅牢なコンテンツを作成すること

4.1 互換性(A)

様々なUAとの互換性を最大化すること

4.1.1 構文解析

成功例 開始タグには対応する閉じタグがある

成功例 要素は使用に応じて入れ子になっている

成功例 IDには重複がない

失敗例 マークアップが正しくない

<p>
  <div></p>
  </div>
<form>
  <form></form>
</form>
<div id="div1"></div>
<div id="div1"></div>
4.1.2 名前(name)・役割(role)及び値(value)

成功例 すべてのUIコンポーネントの名前と役割は解釈可能

成功例 すべてのUIコンポーネントの状態とプロパティは解釈可能

この基準では,独自のUIコンポーネントを作成する場合を対象にしている.したがって,UA標準のUIコンポーネント(input要素など)を利用する場合は,本基準は達成される

失敗例 UIコンポーネントの実装が不完全

例:独自の見た目のチェックボックスを以下のように実装した.これはマウス,キーボードどちらでも操作可能である

<div tabindex="0">独自のチェックボックス</div>

<script>
  const checkbox = document.querySelector("div");

  const toggle = () => checkbox.classList.toggle("checked");
  checkbox.addEventListener("click", toggle);
  checkbox.addEventListener("keypress", (e) => {
    switch (e.key) {
      case " ":
      case "Enter":
        toggle();
    }
  });
</script>

<style>
  div:before {
    content: url('data:image/svg+xml;utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px"><rect style="fill: none; stroke: black; stroke-width: 2" width="16" height="16" /></svg>');
  }
  div.checked:before {
    content: url('data:image/svg+xml;utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px"><rect style="fill: none; stroke: black; stroke-width: 2" width="16" height="16" /><path style="fill: none; stroke: black; stroke-width: 2" d="m 2.6,8 4,5.3 6.6,-10.5" /></svg>');
  }
</style>

→役割が支援技術に伝わっていない.role="checkbox"が必要

支援技術はチェックボックスがあることすらわからない

→状態が支援技術に伝わっていない.aria-checked属性が必要

支援技術は,チェックボックスがチェックされているかどうか利用者に伝えられない

レベルAA

公共サイト1など,アクセシビリティが重要なサイトでは失敗したくないレベル

1. 知覚可能(AA)

ユーザーがコンテンツを知覚(見る,聞く,触る…)できること

1.2 時間依存メディア(AA)

時間に依存するメディアに代替コンテンツがあること

1.2.4 キャプション(ライブ)

成功例 ライブ動画配信にキャプションがある

失敗例 ライブ動画配信にキャプションがない

例:一発ギャグ大会のライブ動画配信を行っているサイトがある.しかしキャプションが提供されていない

→キャプションを提供する.以下のような方法が考えられる

  • ライブが台本通りに進んでいるなら,台本のテキストを提供
  • 速記を用いた高速入力技術
  • 高速タイピング技術(ステノキャプショナー)
  • 音声認識技術(ライブ音声を入力する,またはライブ音声を人間が聞き取って復唱し入力する)

キャプションの例はレベルAの時間依存メディアの説明を参照

1.2.5 音声解説(収録済)

成功例 収録済みの映像に音声解説がある

この基準は,レベルAにおける「1.2.3: 音声解説、又はメディアに対する代替(収録済)」の強化版である.レベルAでは,映像に代替をつければ音声解説は必要なかったが,この基準では必要である.

失敗例 映像に音声解説がない

音声解説の例はレベルAの時間依存メディアの説明を参照

1.3 適応可能(AA)

様々な閲覧方法にコンテンツが適応できること.例えば端末の向きを変えるなど

1.3.4 表示の向き

成功例 コンテンツがデバイスの向き(横向き,縦向き)を制限しない

失敗例 特定の向きでしかコンテンツが見られない

例のサイトをFirefoxのレスポンシブデザインモードで表示している.端末は縦向きで,コンテンツは通常通り表示されている

例のサイトをFirefoxのレスポンシブデザインモードで表示している.端末は横向き.コンテンツは90度横倒しにスタイリングされているため,結果として端末が縦向きの時と同じ表示になっている

コードを見る
<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width" />
    <style>
      body {
        margin: 0;
        padding: 0;
      }
      @media all and (orientation: landscape) {
        body {
          position: absolute;
          top: 0;
          left: 0;
          width: 100vh;
          height: 100vw;
          transform: rotate(90deg) translateY(-100vw);
          transform-origin: top left;
        }
      }
    </style>
  </head>
  <body>
    <h2>縦向きのサイト</h2>
    <p>このWebサイトはスマホの縦向きに最適なデザインです!</p>
  </body>
</html>

→やめるべき

例えば,車椅子の腕にデバイスを横向き固定している利用者もいる.そのような場合このサイトはとても見づらい

他にも,特定の向きでコンテンツを非表示にする,画面が回転されたらアラートを表示するなどの失敗例が考えられる

1.3.5 入力目的の特定

成功例 適切なautocomplete属性を使用している

失敗例 autocomplete属性が不適切

新しいパスワード:<input type="password" />

→どんなパスワード?autocomplete属性がない.autocomplete="new-password"が適切

誕生日:<input type="date" />

→どんな日付?autocomplete属性がない.autocomplete="bday"が適切

生まれた年(例:1996):<input type="text" autocomplete="bday" />

bdayは年月日全体.bday-yearが適切

誕生日:<input type="text" autocomplete="birthday" />

→不正なautocomplete属性値.bdayが正しい

名前(姓):<input type="text" autocomplete="name" />

nameは名前全体.family-nameが適切

表示される名前:<input type="text" autocomplete="username" />

nicknameのほうが適切かもしれない.一方で,nicknameを削除すべきとの声もあるため注意

まとめると,autocomplete属性を正しく設定することには以下の利点がある

  • UAやパスワードマネージャの自動入力により手間を省ける
    • 記憶しなくて良い:特に言語や記憶の障害を持つ場合に有用
    • 入力しなくて良い:特に運動障害を持つ場合に有用
  • UAが目的を解釈し,追加のヒント画像を提供できる:脳性麻痺,脳卒中,頭部損傷,運動ニューロン疾患および学習障害を持つ場合,コミュニケーションに画像を好む場合がある.このような場合にUAは,例えばautocomplete="bday"の項目前にケーキのアイコン,autocomplete="tel"の項目前に電話のアイコンを表示できる

1.4 判別可能(AA)

コンテンツを見やすいものにすること.

1.4.3 コントラスト(最低限)

成功例 サイズの大きなテキストに,3:1以上のコントラストがある

成功例 そうでないテキストに,4.5:1以上のコントラストがある

ここで「サイズの大きなテキスト」とは,以下の条件に当てはまるもの

  • 英文の場合:約24px以上の通常の文字,または約18.6px以上の太字
  • 邦文の場合:約29px以上の通常の文字,または約24px以上の太字

失敗例 十分なコントラスト比がない

十分なコントラストが無いテキストの表示例.サイズの様々なテキストが表示されているが,それぞれのコントラスト比は基準を下回っている

コードを見る
<p>
  <span class="normal">normal size text</span>
  <span class="normal">normal size bold text</span>
  <span class="normal">通常サイズの文字</span>
  <span class="normal">通常サイズの太字</span>

  <span class="big">big size text</span>
  <span class="big">big size bold text</span>
  <span class="big">サイズの大きな文字</span>
  <span class="big">サイズの大きな太字</span>
</p>

<style>
  .normal {
    color: #26a269;
    background: #292929;
  }
  .big {
    color: #792b82;
    background: #9a9996;
  }

  span:nth-of-type(1) {
    font-size: 16px;
  }
  span:nth-of-type(2) {
    font-size: 14px;
    font-weight: bold;
  }
  span:nth-of-type(3) {
    font-size: 20px;
  }
  span:nth-of-type(4) {
    font-size: 16px;
    font-weight: bold;
  }

  span:nth-of-type(5) {
    font-size: 24px;
  }
  span:nth-of-type(6) {
    font-size: 19px;
    font-weight: bold;
  }
  span:nth-of-type(7) {
    font-size: 29px;
  }
  span:nth-of-type(8) {
    font-size: 24px;
    font-weight: bold;
  }

  span {
    padding: 1em;
  }
  p {
    display: flex;
    flex-wrap: wrap;
    gap: 1em;
  }
</style>

→通常サイズのテキストのコントラスト比は4.47:1であり,基準を下回っている.

→サイズの大きなテキストのコントラスト比は2.97:1であり,基準を下回っている

失敗例 前景色または背景色だけを指定している

<p style="color: red">文字色だけ指定</p>

<p style="background: red">背景色だけ指定</p>

→UAの設定によってはコントラスト比を保証できない

特定の前景色と背景色の組み合わせを好む利用者がいる.UAにそれらの組み合わせを設定していた場合,上記の例では前景色だけ,または背景色だけがUAの設定になってしまう.

1.4.4 テキストのサイズ変更

成功例 支援技術なしで200%までテキストサイズをズームできる

今日のモダンブラウザは標準的にズーム機能を備えている.そのため,一昔前にサイト上部で見かけたような,テキストサイズを変更するコントロールの必要性は低くなったと言える.

モダンブラウザのズーム機能を邪魔しないようにコンテンツを制作することが重要である

失敗例 テキストサイズをズームするとコンテンツが利用できなくなる

<div>こんにちは.今日はとてもいい天気ですね.</div>

<style>
  div {
    width: 100%;
    border: 3px solid black;
    overflow: hidden;
    word-break: keep-all;
  }
</style>

これを通常のズームで表示すると以下のようになる

上記のコードを表示した例.通常サイズのテキストで「こんにちは.今日はとてもいい天気ですね.」と枠線の中に書かれている

しかし200%のズームで表示すると以下のようになる

上記のコードを200%に拡大表示した例.通常サイズのテキストで「こんにちは.今日はとてもいい天気で」で枠線からはみ出している.はみ出した部分は表示されていない

→はみ出した部分が表示されていないため,弱視の利用者などはコンテンツを読めない可能性がある

1.4.5 文字画像

成功例 文字画像ではなくテキストが用いられている

成功例 または,文字画像の色,フォント,サイズ,色,背景色をカスタマイズできる

成功例 ただし,必要不可欠なものは例外

必要不可欠な例:あるフォントの販売ページでは,製品の書体を画像で伝えている

失敗例 文字画像が用いられている

<img src="cashback.jpg" alt="キャッシュバック" />

文字画像の例,目立つ太字のフォントで「キャッシュバック」と書かれている

→テキストとCSSを用いて近いスタイルを実現すべき

ロービジョンおよび視線移動に問題のある利用者が,文字のフォント,サイズ,色,背景色,文字間,行間をカスタマイズできない

1.4.10 リフロー

成功例 縦スクロールのコンテンツは,機能を損なうことなくかつ,320pxの横幅で横スクロールせずに利用可能

成功例 横スクロールのコンテンツは,機能を損なうことなくかつ,256pxの縦幅で縦スクロールせずに利用可能

失敗例 縦スクロールコンテンツで横スクロールが必要

<div>
  山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。とかくに人の世は住みにくい。
</div>

<style>
  div {
    margin: auto;
    width: 500px;
  }
</style>

これを600pxの横幅で表示すると以下のようになる.全文が見えている

上記コードを600pxで表示した例.例文がすべて表示されている

しかし320pxの横幅で表示すると以下のようになる.文章を読むには横スクロールが必要

上記コードを320pxで表示した例.例文は画面の横に見切れ,スクロールが必要である

→横スクロールが表示されないようにレイアウトを変える必要がある

失敗例 狭い画面で機能を損なっている

<div>
  <span>新商品のご案内</span>
  <span>製品情報</span>
  <span>この会社について</span>
  <span>お問い合わせ</span>
  <span class="search"><input /><button>検索</button></span>
</div>

<style>
  div {
    display: flex;
    justify-content: space-between;
  }
  @media screen and (max-width: 750px) {
    .search {
      display: none;
    }
  }
</style>

これを800pxの画面幅で見ると,ヘッダー内に検索ボックスが表示されている

上記のコードを800pxの画面幅で表示した例.画面上部にはヘッダーがあり,その中に検索ボックスが表示されている

しかし600pxの画面幅で見ると検索ボックスが消えている

上記のコードを600pxの画面幅で表示した例.画面上部にはヘッダーがあるが,その中に検索ボックスはない

→画面が狭い場合も検索ボックスを表示できるレイアウトにすべき

1.4.11 非テキストのコントラスト

成功例 UIコンポーネント自体および状態を,3:1以上のコントラストで識別できる

成功例 コンテンツ理解に必要なグラフィック部分を,3:1以上のコントラストで識別できる

失敗例 UIコンポーネントに十分なコントラスト比がない

例:以下のチェックボックスのスタイルには十分なコントラスト比がない

十分なコントラスト比がないチエックボックスの画像

コードを見る
<div>チェックされていない</div>
<div class="checked">チェックされている</div>
<div class="focused">フォーカスされている</div>

<style>
  div:before {
    content: url('data:image/svg+xml;utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px"><rect style="fill: none; stroke: %2397979B; stroke-width: 2" width="16" height="16" /></svg>');
  }
  div.checked:before {
    content: url('data:image/svg+xml;utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px"><rect style="fill: none; stroke: black; stroke-width: 2" width="16" height="16" /><path style="fill: none; stroke: %2329AE70; stroke-width: 2" d="m 2.6,8 4,5.3 6.6,-10.5" /></svg>');
  }
  div.focused:before {
    content: url('data:image/svg+xml;utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px"><rect style="fill: none; stroke: %235999E8; stroke-width: 5" width="16" height="16" /></svg>');
  }
</style>

→チェックされていないボックスの枠線は#97979B色であり,背景とは2.91:1のコントラスト比で十分でない

→チェックマークは#29AE70色であり,背景とは2.84:1のコントラスト比で十分でない

→フォーカス時の枠線は#5999E8色であり,背景とは2.93:1のコントラスト比で十分でない

失敗例 グラフィック部分に十分なコントラスト比がない

例:以下では映画の評価を5段階の星で表している

映画の5段階の評価が星で表されている.星には太い枠線がある.うち3つの星は黄色で塗りつぶされている.2つは塗りつぶされていない

→それぞれの塗り色(#FFE620#FFFFFF)のコントラスト比は1.26:1であるため十分でない.

コンテキストの理解のためにいは,それぞれの星を識別する必要がある.2種類の星の違いは塗り色だけであるため,そのコントラスト比が要件に挙がる.

例:以下は円グラフである.それぞれの項目が3段階の青色で表現されている.

円グラフの画像.それぞれの項目が3段階の青色で表現されているが,コントラスト比が十分でない

→コントラスト比が十分でない境界が複数ある

この円グラフでは,各項目の境界がコンテキストにとって重要である.そのため,塗り色のコントラスト比が要件に挙がる.

1番濃い青色(#007EFF)と2番目(#00ACFF)とのコントラスト比は1.53:1であり十分でない.また,2番目(#00ACFF)と3番目(#00E0FF)の青色のコントラスト比は1.57:1であり,これも十分でない.さらに,2番目,3番目の青色と背景色(#FFFFFF)のコントラスト比も基準を下回っている.

例:以下はカレーライスのイラストである

カレーライスのイラスト

→皿の色#DFDFDFとライス部分および背景の色#ffffffとのコントラスト比は1.33:1であり,十分ではない

カレーライスと説明されるイラストにとって,ライスを識別できることはコンテキストの理解に必須である.そのためライス境界部分のコントラスト比が要件に挙がる.

1.4.12 テキストの間隔

成功例 以下のスタイル変更を行ったときにコンテンツを利用できる

  • 行の間隔を,フォントサイズの1.5倍に設定する
  • 段落の間隔を,フォントサイズの2倍に設定する
  • 文字の間隔を,フォントサイズの0.12倍に設定する
  • 単語の間隔を,フォントサイズの0.16倍に設定する

失敗例 テキストの間隔を変更したときにコンテンツを利用できない

例:以下はページトップにバナーのあるサイトである

ページトップにバナーのあるサイト.サイト運営費に関する支援を呼びかけており,支援を行うリンクがある

コードを見る
<div>
  <h1>支援のお願い</h1>
  <p>
    このサイトは皆様からの支援金で運営されております.現在運営資金が少なく大変苦しい状況です.お1人あたりコーヒー1杯分の寄付で結構です.ご検討お願いいたします.
  </p>
  <a href="#">支援はこちらから</a>
</div>

<h1>百科事典</h1>
<p>百科事典とは,あやゆる分野の固有名詞について説明を集めた書籍である.</p>

<style>
  body {
    padding-top: 200px;
    line-height: 1;
  }
  div {
    position: fixed;
    top: 0;
    left: 0;
    width: 300px;
    height: 200px;
    border: 3px solid blueviolet;
  }
</style>

このサイトを行間1.5で表示すると以下のようになる

ページトップにバナーのあるサイト.行間を1.5で表示している.サイト運営費に関する支援をバナーで呼びかけているが,支援を行うリンクが本文と重なってしまい読みにくい

→バナーの文字が本文と重なってしまっている

1.4.13 ホバー又はフォーカスで表示されるコンテンツ

成功例 ホバーやフォーカスで追加のコンテンツが現れる場合は,以下を満たす

  • ポインターやフォーカスを動かさずに表示を消せる
  • 追加のコンテンツにもホバーできる
  • ポインターやフォーカスを移動するまで表示が継続される

失敗例 追加のコンテンツが上記条件を満たさない

例:以下はツールチップの実装例である.ヘルプという文字をホバーするとチップが表示される.チップは3秒経過すると非表示になる

ツールチップの実装例.郵便番号の入力欄に「ヘルプ」というテキストがあり,そこにマウスをホバーすると,ツールチップが表示される.ツールチップには,入力規則や郵便番号検索へのリンクがある

コードを見る
<label>
  郵便番号:
  <input />
</label>
<span>ヘルプ</span>
<div>
  郵便番号は以下のルールで入力してください
  <ul>
    <li>郵便マーク〒は入力しないでください</li>
    <li>半角数字で入力してください</li>
    <li>ハイフンは省いてください</li>
  </ul>
  郵便番号がわからない方:<a href="#">郵便番号検索</a>
</div>

<script>
  const tooltip = document.querySelector("div");
  const helpText = document.querySelector("span");

  const timer = null;
  helpText.addEventListener("mouseenter", () => {
    tooltip.style.display = "block";
    clearTimeout(timer);
    setTimeout(() => {
      tooltip.style.display = "none";
    }, 3000);
  });
  helpText.addEventListener("mouseleave", () => {
    tooltip.style.display = "none";
  });
</script>

<style>
  div {
    display: none;
    border: 3px solid blue;
  }
</style>

→ポインターを移動させないとツールチップを非表示にできない

利用者は意図せずフォーカスしてしまったかもしれない.例えば,画面を特に拡大している場合はポインターを外しにくいかもしれない.

→追加コンテンツにホバーできない

したがって,「郵便番号検索」リンクはマウスでクリックできない

→表示が継続されない

3秒でツールチップが消えてしまうため,内容を最後まで読めない可能性がある

2. 操作可能(AA)

ナビゲーションは操作可能でなければならない

2.4 ナビゲーション可能(AA)

利用者がサイト内で迷わないこと

2.4.5 複数の手段

成功例 Webサイトの中で,あるページを見つける複数の手段がある

失敗例 あるページを見つける手段が1つしかない

例:ある大手家電メーカーが提供するプリンター説明書ページには,以下の操作のみでアクセス可能

  1. トップページ:「製品情報」を選択
  2. 製品情報ページ:「個人向け」を選択
  3. 個人向け製品ページ:「PC周辺機器」を選択
  4. PC周辺機器製品ページ:「プリンター」を選択
  5. プリンター製品ページ:型番「PRT-123-4567」を選択
  6. 型番「PRT-123-4567」の製品ページ:「説明書」を選択
  7. やっと目的のものにたどり着けた

→検索機能を設置すべき

特に,視覚障害のある人は,画面を拡大しながらページを移動するよりも検索を好むかもしれない

→サイトマップを提供すべき

特に,認知障害のある人は,複数のページを移動するよりも全体を見渡せるマップを好むかもしれない

2.4.6 見出し及びラベル

成功例 見出しおよびラベルはわかりやすい

失敗例 見出しやラベルがわかりにくい

<h2>今日の日記</h2>
<p>水族館に行った.魚がいっぱいいた</p>

<h2>日記</h2>
<p>進捗がゼロだった</p>

<h2> </h2>
<p>ねむい</p>

→見出しが本文を要約していない

→最後の見出しにテキストを入れ忘れている(おそらく眠かったため

利用者はサイトの構造をつかみにくい

ログインID:<input />

→ラベルはあるがわかりにくい

→IDってメールアドレスだっけ?その場合@の前まで?後も必要?

注意:この基準とは別に,ラベルはUIコンポーネントのアクセシブルな名前として関連付けられると良い.詳しくは4.1.2 名前(name)・役割(role)及び値(value)を参照

失敗例 見出しレベルが飛んでいる

<h1>岡山の歴史</h1>

<h3>紀元前</h3>
<p>耕作の発達した岡山県では…</p>

→例えばスクリーンリーダーの利用者は「見出しレベル2を読み飛ばしたかな?」と困惑する

2.4.7 フォーカスの可視化

成功例 キーボードで操作できるUIには,フォーカスインジケータがある

失敗例 フォーカスインジケータを無効化している

<button>5億年</button>

<style>
  /* クリックしたときの謎の枠線を消すためにつけてみた */
  button {
    outline: none;
  }
</style>

→キーボードで操作できなくなる

失敗例 フォーカスインジケータが見分けづらい

例:ユーザーの環境は「Ubuntu 22.04.1 LTS」のデフォルトである.この環境のフォーカスインジケータはオレンジ色である

Ubuntuのデフォルトのボタンのデザイン

ボタンにUbuntuのデフォルトのフォーカスインジケータが表示されている.オレンジ色

ここでページのデザインに変更があり,背景がオレンジ色になったとする

<button>5億年</button>

<style>
  body {
    background-color: orangered;
  }
</style>

ボタンにUbuntuのデフォルトのフォーカスインジケータが表示されている.背景が同じような色なので見分けづらい

→フォーカスインジケータは表示されているが,背景の色と似ているので見分けづらい

ページのデザインに合わせて,独自のフォーカスインジケータを作成してもいいかもしれない.

3. 理解可能(AA)

理解しやすいコンテンツを作ること

3.1 読みやすさ(AA)

読みやすいコンテンツを作ること

3.1.2 一部分の言語

成功例 コンテンツ内に別の言語がある場合,その言語が指定されている

成功例 固有名詞や技術用語に言語を指定する必要はない

失敗例 言語が指定されていない

<!DOCTYPE html>
<html lang="ja">
  <body>
    <p>Linusは言った</p>

    <blockquote>
      <p>Given enough eyeballs, all bugs are shallow.</p>

      <p>訳:大勢の目があれば,すべてのバグは大した問題ではない</p>
    </blockquote>
  </body>
</html>

<p lang="en">Given enough eyeballs, all bugs are shallow.</p>とするのが適切である

UAや支援技術の,表示や音声合成に対するヒントになる.

3.2 予測可能(AA)

コンテンツの挙動が予測可能であること

3.2.3 一貫したナビゲーション

成功例 繰り返されるナビゲーションはすべて一貫している

失敗例 ページによってナビゲーションが変わる

例:ある市のサイトがある.トップページのナビゲーションは以下のようになっている

<nav>
  <ul>
    <li><a>観光地</a></li>
    <li><a>よくある質問</a></li>
    <li><a>今日の市長</a></li>
  </ul>
</nav>

ここで,観光地を選択する.観光地のページのナビゲーションは以下のようになっている

<nav>
  <ul>
    <li><a>トップページ</a></li>
    <li><a>今日の市長</a></li>
    <li><a>よくある質問</a></li>
  </ul>
</nav>

→順番が一貫していない

観光地リンクが消え,トップページリンクが現れた.「今日の市長」と「よくある質問」の順番が入れ替わった.

3.2.4 一貫した識別性

成功例 同じ機能のコンポーネントは一貫して識別できる

失敗例 同じ機能なのに見た目が違う

<!-- あるページでは -->
<p>
  <label>高評価する<button></button></label>
</p>

<!-- しかし別のページでは -->
<p>
  <label>高評価する<button>👍</button></label>
</p>

<style>
  button {
    color: white;
    background-color: black;
  }
</style>

これは以下のように表示される

2つの高評価ボタンのスクリーンショット.1つは上向き矢印アイコン.もう1つはサムズアップアイコン

失敗例 同じ機能なのにテキストが違う

<!-- あるページでは -->
<form>
  <label>名前:<input /></label>

  <button>送信</button>
</form>

<!-- しかし別のページでは -->
<form>
  <label>好きな色:<input /></label>

  <button>完了</button>
</form>

→どちらもフォームの送信ボタンだがテキストが異なる

同じ機能のUIに一貫性を持たせることで混乱を避け,また「慣れ」によって利用者の認知的負荷を軽減できる.

3.3 入力支援(AA)

間違いを防ぎ,修正を支援すること

3.3.3 エラー修正の提案

成功例 入力エラーの修正方法を提案できる場合,それが提示される

失敗例 エラーの修正方法が不十分

<label>
  <span style="color: red">使用できない文字が含まれています</span>
  備考:<textarea aria-invalid="true"></textarea>
</label>

→どの文字が?

<label>
  <span style="color: red">画像サイズが大きすぎます</span>
  アイコン画像:<input aria-invalid="true" type="file" />
</label>

→どのサイズまでならOK?

<label>
  <span style="color: red">パスワードが違います</span>
  ログインパスワード:
  <input aria-invalid="true" type="password" autocomplete="current-password" />
</label>

→修正方法がない

例えば

  • 「パスワードをお確かめください」というメッセージと,パスワードを表示するボタンを設置する
  • 「パスワードは英数字で記号を含みます」といったヒントを提示する
  • 「パスワードリセットはこちら」というリンクを設置する
3.3.4 エラー回避(法的、金融、データ)

成功例 法的行為や金融取引が生じる操作には以下のいずれかの機能がある

  • 操作を取り消せる
  • 入力がチェックされ,不正な場合は修正できる
  • 操作の完了前に利用者が内容を確認および修正できる

失敗例 操作ミスが重大な結果を招く

例:あるオンラインバンキングサイトがある.ここでは資金の送金が行える

シナリオ:利用者は4,000円を別口座に送金したい.タッチパネルでWebサイトを操作している.以下の操作を行った

  1. 画面のテンキーを使用して「4」「0」「0」「0」と入力した
  2. 送金ボタンを押そうとしたが,誤って画面の「万」ボタンにも同時に触れてしまった
  3. 4,000万円の送金が即座に行われてしまった

→操作を取り消せると良かった

システムが実際の送金を行うのは,ボタンが押されてから10分後というようにして,一定時間内なら取り消しできると良かった

→入力がチェックされると良かった

一定以上の金額には,「金額が大きいです.本当に送金しますか?」といったダイアログが表示されると良かった

→確認画面があれば良かった

送金前に「内容を確認してください」という画面があればキャンセルできた

4. 堅牢(AA)

様々なUAが解釈できるように,堅牢なコンテンツを作成すること

4.1 互換性(AA)

様々なUAとの互換性を最大化すること

4.1.3 ステータスメッセージ

成功例 ステータスメッセージは解釈可能で,利用者はそれにフォーカスしなくても認識できる

失敗例 ステータスメッセージが解釈可能でない

例:あるブログサイトでは保存ボタンを押すと,画面左下に「成功しました」というメッセージ(スナックバー)が一定時間表示される

ブログサイトのスクリーンショット.日記の入力欄と保存ボタンがある.左下には「保存しました」というメッセージが出ている

<form>
  <label>日記:<textarea></textarea></label>

  <button type="button">保存</button>
</form>

<div>成功しました</div>

<style>
  /* 省略 */
</style>

<script>
  // 省略
</script>
すべてのコード
<form>
  <label>日記:<textarea></textarea></label>

  <button type="button">保存</button>
</form>

<div>成功しました</div>

<style>
  div {
    display: none;
    position: absolute;
    bottom: 1em;
    left: 1em;
    padding: 1em;
    border: 1px solid black;
  }
</style>

<script>
  const snackbar = document.querySelector("div");
  const saveButton = document.querySelector("button");
  saveButton.addEventListener("click", () => {
    snackbar.style.display = "block";
    setTimeout(() => {
      snackbar.style.display = "none";
    }, 2000);
  });
</script>

→目の見えない人は「保存しました」のメッセージに気づけない

<div role="status" aria-live="polite">成功しました</div>が正しい

失敗例 ステータスメッセージがうるさい

例:ある広告がrole="alert"およびaria-live="assertive"を使用している

→スクリーンリーダーは重要でない情報を優先して読み上げてしまう

レベルAAA

最高のアクセシビリティを提供するなら失敗したくない,プロ用のレベル.コンテンツによっては,そもそも達成不可能な基準も2

1. 知覚可能(AAA)

ユーザーがコンテンツを知覚(見る,聞く,触る…)できること

1.2 時間依存メディア(AAA)

時間依存のメディアに代替があること

1.2.6 手話(収録済)

成功例 収録済みの動画の,音声トラックに手話通訳がある

失敗例 音声に手話通訳がない

→自然言語がキャプションの言語と異なる人は,それを十分に理解できないかもしれない

→自然言語が手話である人は,キャプションが読めないかもしれない

1.2.7 拡張音声解説(収録済)

成功例 音声解説だけでは映像の意味を伝達しきれない場合,拡張音声解説が提供されている

失敗例 拡張音声解説が提供されていない

例:ある数学の動画教材がある.教師が黒板を使いながら問題を解説している.板書は音声解説で提供されているが,それだけである.

→問題の合間に動画を一時停止し,拡張音声解説を入れるのが望ましい

目の見える人は黒板を見ながら教師の説明を聞ける.一方で見えない人はそれができない.板書を一度読み上げられても,それを覚えておける量には限界がある.したがって一時停止しての解説が必要.

1.2.8 メディアに対する代替(収録済)

成功例 収録済みの音声および映像には代替(書き起こし)がある

注意:音声解説によって「1.2.3 音声解説、又はメディアに対する代替(収録済)」と「1.2.5 音声解説(収録済)」を達成していた場合は,新たに代替も作成する必要がある

失敗例 代替がない

例:一発ギャグ大会の動画があるが,代替は提供されていない.

→目が見えず耳も聞こえない人は一発ギャグを楽しめない

例えば台本のような書き起こしを提供すれば,点字ディスプレイなどで読める

1.2.9 音声のみ(ライブ)

成功例 ライブ音声配信にキャプションや代替がある

失敗例 ライブ音声配信にキャプションや代替がない

例:漫談の音声をライブ配信しているサイトがある.しかしキャプションが提供されていない

→キャプションを提供する.以下のような方法が考えられる

  • ライブが台本通りに進んでいるなら,台本のテキストを提供
  • 速記を用いた高速入力技術
  • 高速タイピング技術(ステノキャプショナー)
  • 音声認識技術(ライブ音声を入力する,またはライブ音声を人間が聞き取って復唱し入力する)

1.3 適応可能(AAA)

様々な環境にコンテンツが適応できること

1.3.6 目的の特定

成功例 コンテンツ(UIコンポーネント,アイコン,領域など)の目的は解釈可能

失敗例 目的が解釈可能でない

<form><input /><button>検索</button></form>

<form role="search">が適切

<main>
  <h1>日記:2022/09/28</h1>
</main>

<main>
  <h1>日記:2022/09/27</h1>
</main>

→ページに複数のmainランドマークがあるべきでない

<ul>
  <li><a>トップページ</a></li>
  <li><a>製品情報</a></li>
  <li><a>会社情報</a></li>
  <li><a>お問い合わせ</a></li>
</ul>

nav要素を用いてナビゲーションロールをつけるべき

<div>相互リンク集</div>

role="complementary"によって補足情報であることを明示すると良い

まとめると,コンテンツの目的を示すことは以下のことに役立つ

  • ナビゲーション
    • 例:ヘッダーなどをスキップしてmainランドマークに移動する
  • 簡素化
    • 例:main以外の要素を隠して表示する
  • 追加情報の提示
    • 例:語彙が限られる人などが好むシンボルを追加で提示する(以下画像参照.将来的には,data-symbolなどによる意味の提示によって,UAは利用者それぞれが好むシンボルを表示できるかもしれない)

以下は追加情報を提示する前のページ

追加情報を提示する前のページ.見出しには「How to Make Good Cup of Tea」とある

以下はページにシンボルを追加した状態

ページに追加のシンボルが表示されている.例えば見出しのHowという単語の左に,その単語を意味するシンボル画像がある

以下は,先程のページを別のシンボルセットで表示している状態.利用者それぞれが好むシンボル画像でページを利用できる.

ページに追加のシンボルが表示されているが,前の画像とは違うシンボルセットを用いて表示されている

画像の出典: 1.2.4.1 Proof of Concept: Symbol Example - WAI-Adapt Explainer

1.4 判別可能(AAA)

コンテンツを見やすいものにすること.

1.4.6 コントラスト(高度)

成功例 サイズの大きなテキストに,4.5:1以上のコントラストがある

「サイズの大きなテキスト」の定義は1.4.3 コントラスト(最低限)の説明を参照.

成功例 そうでないテキストに,7:1以上のコントラストがある

この基準は,1.4.3 コントラスト(最低限)の強化版である.基準となるコントラスト比の閾値が引き上げられている.

失敗例 十分なコントラスト比がない

十分なコントラストが無いテキストの表示例.サイズの様々なテキストが表示されているが,それぞれのコントラスト比は基準を下回っている

コードを見る
<p>
  <span class="normal">normal size text</span>
  <span class="normal">normal size bold text</span>
  <span class="normal">通常サイズの文字</span>
  <span class="normal">通常サイズの太字</span>

  <span class="big">big size text</span>
  <span class="big">big size bold text</span>
  <span class="big">サイズの大きな文字</span>
  <span class="big">サイズの大きな太字</span>
</p>

<style>
  .normal {
    color: #211512;
    background: #a1a1a1;
  }
  .big {
    color: #f8e45c;
    background: #ad4800;
  }

  span:nth-of-type(1) {
    font-size: 16px;
  }
  span:nth-of-type(2) {
    font-size: 14px;
    font-weight: bold;
  }
  span:nth-of-type(3) {
    font-size: 20px;
  }
  span:nth-of-type(4) {
    font-size: 16px;
    font-weight: bold;
  }

  span:nth-of-type(5) {
    font-size: 24px;
  }
  span:nth-of-type(6) {
    font-size: 19px;
    font-weight: bold;
  }
  span:nth-of-type(7) {
    font-size: 29px;
  }
  span:nth-of-type(8) {
    font-size: 24px;
    font-weight: bold;
  }

  span {
    padding: 1em;
  }
  p {
    display: flex;
    flex-wrap: wrap;
    gap: 1em;
  }
</style>

→通常サイズのテキストのコントラスト比は6.88:1であり,基準を下回っている.

→サイズの大きなテキストのコントラスト比は4.38:1であり,基準を下回っている

1.4.7 小さな背景音、又は背景音なし

成功例 収録済みの発話で音楽表現を意図していないもの(例:ポッドキャストなど)は以下のいずれかである

  • 背景音(BGMなど)を含まない
  • 背景音を消せる
  • 背景音は発話よりも20デシベル以上低い

失敗例 BGMが大きすぎて発話が聞き取れない

音声サンプルは公式のものを参照

出典: 非発話音が発話音声コンテンツより少なくとも 20 デシベル低くなるように、音声ファイルを編集する

1.4.8 視覚的提示

成功例 テキストブロックは以下を満たす

  • 利用者が前景色と背景色を選択できる
  • 幅が80文字(全角文字の場合は40文字)を超えない
  • 均等割り付け,両端揃えされていない
  • 行送りが少なくとも1.5文字分ある
  • 段落の間隔が行送りの1.5倍以上ある
  • テキストは200%まで拡大でき,利用者の全画面表示で横スクロールが発生しない

失敗例 文字数,行間,段落の間隔が適切でない

幅の文字数,行間,段落の間隔が適切でない表示例.サンプルテキストは「初カキコども」コピペ

<p>
  「初カキコども」は,2ちゃんねるのオカルト板への書き込み.今や伝説のコピペである.
</p>

<p>
  初カキコ…ども… 
  俺みたいな中3でグロ見てる腐れ野郎、他に、いますかっていねーか、はは 
  今日のクラスの会話 あの流行りの曲かっこいい とか あの服ほしい とか 
  ま、それが普通ですわな かたや俺は電子の砂漠で死体を見て、呟くんすわ it’a
  true  wolrd.狂ってる?それ、誉め言葉ね。 好きな音楽 eminem 
  尊敬する人間 アドルフ・ヒトラー(虐殺行為はNO) 
  なんつってる間に4時っすよ(笑) あ~あ、義務教育の辛いとこね、これ 
</p>

<style>
  p {
    width: 50em;
    line-height: 1;
    margin: 0.5em 0;
    padding: 0;
  }
</style>

→幅が約50文字ある

改行を追うのが難しい人もいるかもしれない

→行間が狭すぎる,もしくは無い

これも改行を追いづらくする要因である

→段落間が近すぎる

読者は段落が変わったことに気づけないかもしれない

失敗例 均等割り付け,両端揃えされている

英文が均等割付で表示されている例

<p>
  my first time writing... Guys... Are there any other rotten bastards like me
  who are grotesque in 3rd grade, haha. today's class conversation. That trendy
  song is cool or that girl who wants that dress. oh that's normal. On the other
  hand, when I see a corpse in the electronic desert, I mutter. it's a true
  world. Am I crazy? That's a compliment. Favorite music: eminem. Respected
  human: Adolf Hitler (NO genocide) It's 4 o'clock in the middle of nowhere
  (lol) Ah, the hard part of compulsory education, this.
</p>

<style>
  p {
    text-align: justify;
    line-height: 1;
  }
</style>

→普通に左揃えで表示すべき

人によっては,特に認知に障害のある人には,リバー(白い川とも)が認識の邪魔になってしまう.

英文が均等割付で表示されている例.リバーが赤線で示してある

失敗例 前景色および背景色を変える方法がわからない

→例えば,変更方法を示した説明を追加する

説明の例:ChromeとFirefoxではStylusというアドオンで色を変更できます

1.4.9 文字画像(例外なし)

成功例 文字画像ではなくテキストが用いられている

成功例 ただし,必要不可欠なものは例外

→必要不可欠な例は,1.4.5 文字画像を参照

この基準は,1.4.5 文字画像の強化版である.

1.4.5では文字画像の見た目をカスタマイズできる場合に例外が認められていた.しかし本基準では認められない.

失敗例 文字画像が用いられている

→失敗例は1.4.5 文字画像を参照

2. 操作可能(AAA)

UIコンポーネントは操作可能でなければならない

2.1 キーボード操作可能(AAA)

キーボードで操作できること

2.1.3 キーボード(例外なし)

成功例 コンテンツのすべての機能はキーボードで操作できる

この基準は,2.1.1 キーボードの強化版である.

2.1.1には例外事項があったが,本基準にはない.したがって,軌跡に依存する機能はそもそもこの基準を達成不可能である.

失敗例 キーボードで操作できない機能がある

→失敗例は2.1.1 キーボードを参照

2.2 十分な時間(AAA)

コンテンツを読み,使用する十分な時間があること

2.2.3 タイミング非依存

成功例 コンテンツに制限時間がない

成功例 制限時間がある場合,次のいずれかである

  • リアルタイムのイベント(例:オークション)
  • 制限時間が必要不可欠

この基準は,2.2.1 タイミング調整可能の強化版である.制限時間の例外は,リアルタイムまたは必要不可欠な場合に限られる.

失敗例 リアルタイムでも必要不可欠でもないコンテンツに制限時間がある

→失敗例は2.2.1 タイミング調整可能を参照

2.2.4 割り込み

成功例 緊急を要さない割り込みは,抑制または停止できる

失敗例 割り込みが抑制または停止できない

例:為替情報を提供するページがある

<!-- 為替レートが数秒ごとにJavaScriptでリアルタイム更新される -->
<span role="alert" aria-live="assertive">
  現在の為替レートは,144.31 JPY/USD
</span>

<h2>今週の為替状況</h2>
<p>今週は特に大きな動きがありました.それは……</p>

→例えばスクリーンリーダーで本文を読んでいる最中に,更新された情報が割り込んで読まれてしまう

更新を一時停止するような仕組みが望ましい

2.2.5 再認証

成功例 認証セッションが切れた場合でも,データを失うことはない

失敗例 セッションが切れた場合にデータを失ってしまう

例:航空券の購入

  1. 認知障害をもつ利用者が航空券購入の長いフォームを進めている
  2. 障害のため入力に時間がかかったが,なんとか「購入」ボタンを押した
  3. しかしセッションが切れてしまっており,ログイン画面にリダイレクトされた
  4. ログインすると同じフォーム画面に戻ってきた
  5. しかし,入力内容は消えていた

→入力内容が失われないような仕組みを実装すべき

2.2.6 タイムアウト

成功例 利用者の無操作によってデータが失われる可能性がある場合は,それが警告される

成功例 または,無操作のタイムアウトが20時間以上

失敗例 タイムアウト時間が書かれていない

タイムアウトの時間が書かれていないフォーム.「プライバシー保護のため,一定時間以内に送信されない回答は破棄されます」とあるが,その時間が書かれていない

<fieldset>
  <legend>どちらかに投票してください</legend>

  <label><input type="radio" name="vote" />テツ</label>
  <label><input type="radio" name="vote" />トモ</label>
</fieldset>

<p>※プライバシー保護のため,一定時間以内に送信されない回答は破棄されます</p>

→具体的にどれくらいの時間でタイムアウトするのか書くべき

2.3 発作と身体的反応(AAA)

発作を起こすようなコンテンツは作成しないこと

2.3.2 3 回の閃光

成功例 どの1秒間にも3回の閃光を放つものがない

ここでは基準 2.3.1 3回の閃光、又は閾値以下で許可されていた閾値が無い

失敗例 1秒間に3回の閃光を放つものがある

例:ユーザーの注意をひくための点滅する広告など

2.3.3 インタラクションによるアニメーション

成功例 インタラクションによるアニメーションを無効化できる

成功例 インタラクションによるアニメーションが必要不可欠である

失敗例 不要なパララックス効果

例:カレーのランディングページがある.画面をスクロールすると,カレーライスのイラストが近づいたり離れたり,無数のにんじんが視差効果を生み出したり,宣伝文が横から飛び出たりする.

→アクセシビリティの観点からはパララックスをやめるべき.または効果を必要なもののみに抑えるべき

余計な動きは,特に前庭障害を持つ人へ大きく影響する.コンテンツに集中できなかったり,ひどい場合には回復のためにベッドでの安静が必要になったりする.

2.4 ナビゲーション可能(AAA)

利用者がサイト内で迷わないこと

2.4.8 現在位置

成功例 サイト内で利用者の位置に関する情報が利用できる

失敗例 現在位置を示す情報がない

例:プリンターの説明書を探している

  1. 利用者は,「PRT-123-4567」の説明書を探している
  2. 検索エンジンの結果,「PRT-122-4567」の説明書が見つかった.これは探しているものとは微妙に違う.
  3. 利用者は1つ上の階層のページに行こうと考えたが,そもそも現在ページがどこなのかわからなかった

→例えばパンくずリストが提供されていればよかった

パンくずリストの例:「製品情報 > 個人向け > PC周辺機器 > プリンター > PRT-122-4567」

2.4.9 リンクの目的(リンクのみ)

成功例 リンクのテキスト単独で,その目的が判断できる

失敗例 リンクのテキスト単独で,その目的が判断できない

<a>ダウンロードする</a>

→何を?

<a>今年度決算報告書(Word)</a> <a>PDF版</a>

→何のPDF版?

<a>ここをクリック</a>するとヘルプが開きます

→「ここをクリック」するとどうなる?リンクテキスト単独では判断できない

2.4.10 セクション見出し

成功例 セクションには見出しがある

失敗例 見出しが無い

<form><input /><button>岡山の情報を検索</button></form>

<p>岡山県の首都について,岡山市は日本の政治,経済,国防など……</p>

<p>岡山の歴史について,紀元前,太古の岡山県民は……</p>

→見出しをつけるべき

上記のフォームと段落はそれぞれが独立したセクションとみなせる.それぞれの直前に見出しを配置できる.

これは非常に重要なことである.多くの利用者がコンテンツを流し読みするという調査結果がある.また,約67%のスクリーンリーダー利用者は,見出しによって情報を見つけるという調査結果もある.これは検索機能やランドマークに比べて高い数字である.

2.5 入力モダリティ(AAA)

様々な入力機器で操作しやすいこと

2.5.5 ターゲットのサイズ

成功例 ポインタ入力のターゲットサイズは44px × 44px以上

成功例 ただし以下は例外

  • 同じ機能の大きいボタンがある
  • インラインである:リンク,文中のボタンなど
  • UAが提供する機能をそのまま使っている
  • 必要不可欠

失敗例 ターゲットが小さい

<p>このボタンは,それを操作するには狭すぎる</p>
<button>狭い</button>

<style>
  button {
    width: 43px;
    height: 43px;
  }
</style>

これは以下のように表示される

幅と高さが43pxのボタンのスクリーンショット

→特にタッチ操作は精度が荒い入力方法である.このサイズだとギリギリ操作が難しい人もいるかもしれない

2.5.6 入力メカニズム非依存

成功例 コンテンツが入力方法を制限しない

失敗例 コンテンツが入力方法を制限している

例1:不十分なファストタップの実装

<div>乱数:<span></span></div>
<button>更新</button>

<script>
  const span = document.querySelector("span");
  const button = document.querySelector("button");

  // これだとスマホで遅い
  // button.addEventListener("click", () => (span.innerText = Math.random()));

  // これだと早い!
  button.addEventListener("touchend", () => (span.innerText = Math.random()));
</script>

→マウスで操作できない

補足:このファストタップの実装は簡易的なため,2.5.2 ポインタのキャンセルにも失敗する

例2:例1をマウス・キーボードにも対応させた

<div>乱数:<span></span></div>
<button>更新</button>

<script>
  const span = document.querySelector("span");
  const button = document.querySelector("button");

  if (window.TouchEvent || "ontouchend" in window) {
    // タッチスクリーン用
    button.addEventListener("touchend", () => (span.innerText = Math.random()));
  } else {
    // マウス・キーボード用
    button.addEventListener("click", () => (span.innerText = Math.random()));
  }
</script>

それでもなお,以下のようなケースで問題がある

ケース1:タッチ操作が可能なPCを使用している

→キーボードで操作できない

ケース2:タブレットに外付けのキーボードを接続した

→やはりキーボードで操作できない

ケース3:ページ読み込み後に,外付けのタッチスクリーンを接続した

→タッチ操作できない

ケース4:ページ読み込み後に,外付けのタッチスクリーンを切断した

→ページをリロードするまで,ボタンを操作する方法はない

3. 理解可能(AAA)

理解しやすいコンテンツを作ること

3.1 読みやすさ(AAA)

読みやすいコンテンツを作ること

3.1.3 一般的ではない用語

成功例 一般的でない単語の定義を特定できる

失敗例 単語の定義が特定できない

<h2>障害のお知らせ</h2>
<p>
  現在サービスが使用不可能な状態です.ソースコードのバージョン管理を誤り,一部の機能が先祖返りしています
</p>

→「ソースコード」「バージョン管理」「先祖返り」は,専門家でない読者には伝わらない

ページの最後に用語集を定義し,そこに単語をリンクさせると良い.

(もっとも,一般向けの説明には専門用語を極力使用しないと良い)

3.1.4 略語

成功例 略語のもとの語を特定できる

失敗例 略語のもとの語がわからない

<p>
  DDDは新しいソフトウェア開発手法である.締切が間近である人間のアドレナリンを利用して効率を高める.
</p>

→「DDD」が何の略なのか示されていない

例えば,「DDD(deadline-driven development)は新しいソフトウェア開発手法である」というように,初出の際に説明する.またはaddr属性を用いても良い.

3.1.5 読解レベル

成功例 固有名詞や題名を取り除いた文章は,中学3年生にも理解できる

成功例 または,中学3年生でも理解できるバージョンが提供されている

失敗例 文章が簡潔でない

例:「美味しいコーヒーの淹れ方」というページには以下の説明がある

必要な器具をあらかじめ温めたうえで水素と酸素の化合物であるDHMOを95度まで加熱しペーパーフィルターの底と側面の接着部分を折ってドリッパーに軽く押さえつけるようにセットしフィルターにコーヒー粉を入れた上でドリッパーを軽く降って粉の表面を平らに均し少量の加熱されたDHMOを乗せるように注ぎ入れて20秒ほど蒸らし待つとサーバーに抽出物がポタポタとたれてくるのが確認できるためコーヒー粉の中心に小さな「の」の字を描くように加熱されたDHMOを3回に分けてまず80cc次に40cc最後に20ccと注ぎ抽出物をカップに注ぎ入れたら完成

→読みにくい

一文が長い,句読点がない,言い回しが難しいなどの要因が考えられる.

この文章が中学3年生に理解可能であるかを定量的にテストすることは難しい課題だが,いくつかの研究やツールが存在する.

3.1.6 発音

成功例 発音がわからないと単語の意味が不明瞭になる場合,発音を特定できる

失敗例 発音がわからない

<p>とある魔術の禁書目録は,日本のライトノベルである</p>

<p>主人公である上条当麻は,とある事件に巻き込まれる</p>

→「禁書目録」および「上条当麻」の読みを提供すべき

タイトルと主人公の名前は作中に頻出する.特に言語障害のある人や音声読み上げを利用している人にとって有用である.

「禁書目録(インデックス)」のように読みをカッコ書きするか,またはruby要素を利用できる.

3.2 予測可能(AAA)

コンテンツの挙動が予測可能であること

3.2.5 要求による変化

成功例 利用者の意図しないコンテキスト変化がない

成功例 または,利用者の意図しないコンテキストの変化を止める仕組みがある

ここでの「利用者の意図しないコンテキストの変化」とは,例えば以下のようなものである

本基準では,上記を含むすべての意図しないコンテキストの変化を禁止している

失敗例 利用者の意図しないコンテキストの変化があり,それを止められない

3.3 入力支援(AAA)

間違いを防ぎ,修正を支援すること

3.3.5 ヘルプ

成功例 コンテキストに応じたヘルプが利用可能

失敗例 ヘルプが利用できない

例:年末調整を行うフォームがある

<label>源泉控除対象配偶者の氏名:<input /></label>

→利用者によっては「源泉控除対象配偶者」がわからないかもしれない.この用語を説明するヘルプリンクを設置すると良い

例:サーバーのCPU使用率やネットワークトラフィック量など,インフラ業務のためのダッシュボードがある.特にヘルプ機能はない

→初めての利用者のために,使い方をまとめたドキュメントへのリンクがあると良い

→または,画面を実際に操作しながら使い方を学ぶ「ヘルプツアー」機能があっても良い

3.3.6 エラー回避(すべて)

成功例 利用者が情報を送信する操作には以下のいずれかの機能がある

  • 操作を取り消せる
  • 入力がチェックされ,不正な場合は修正できる
  • 操作の完了前に利用者が内容を確認および修正できる

この基準は,3.3.4 エラー回避(法的、金融、データ)の強化版である.

3.3.4 エラー回避(法的、金融、データ)では,対象となる操作は,法的行為や金融取引などの重要なものに限定されていた.しかし本基準では,情報を送信するすべての操作が対象である.

失敗例 操作ミスを取り返せない

→失敗例は3.3.4 エラー回避(法的、金融、データ)を参照

おわりに

正直に言って,WCAGへの適合はレベルAであっても大変だし,追加コストもかかります.例えば動画を埋め込んでいる場合,レベルAでは「キャプションと音声解説か代替用意しろ」とあります.我々コンテンツの作り手としては 「え?字幕用意するの?この動画プレーヤーって字幕対応してたっけ……?音声解説?誰が読み上げるんだ?声優を雇うのか?合成音声でもいいのか?あ,もしくは書き起こしか?ビジュアルデザインは……」 と,おおわらわです.

一方で,そこまでコストがかからない達成方法もあります.例えば「装飾画像のaltには空文字を指定する」は,知ってたら2秒でコード書いて終わりです.

しかしその効果は小さくありません.私は実際にスクリーンリーダーを使ってみて実感しました.よくわからん枠線で毎回「ラベルのない画像」とか「枠線画像」などと読まれるのはシンプルにストレスです.それがなくなるだけでも体験は格段に良くなります.

というわけで「まずはできることろから3」というのがコスパの良い方針ではないでしょうか.例えばこの記事で「やっちゃダメなこと」が認知され,それで世の中が少しでもアクセシブルになるなら嬉しいです.

まだまだアクセシビリティ初心者なので,間違いを見つけた場合はマサカリをお願いします.

素材の出典


  1. みんなの公共サイト運用ガイドライン(2016年版)によれば,「適合レベル AA に準拠していないホームページ等」について「速やかに、ウェブアクセシビリティ方針を策定・公開し、遅くとも 2017 年度末までに適合レベル AA に準拠」とある
  2. 適合を理解するによれば「コンテンツの中には、レベル AAA 達成基準のすべてを満たすことのできないものもあるため、サイト全体の一般的な方針としてレベル AAA での適合を要件とすることは推奨されない。」
  3. まぁ私は一般企業のエンジニアなのでこんなことが言えます.公共サイトではAA適合が推奨されているので,対応されているエンジニアの方々には頭が上がりません

続けて読む…

【配布あり・編集可能】Blenderでパチンコ文字

2022/01/01

Credits(Frums)をマジのターミナルで

2021/04/29

よわよわエンジニアがTAPL(型システム入門)を読んだら

2022/05/02

Blenderと魚

2017/06/13

ECMA-262を読んだ日

2022/06/10

夏だからGatsbyのランタイム全部消す

2021/08/02

書いた人

sititou70のアイコン画像
sititou70

都内の社会人エンジニア3年生。Web技術、3DCG、映像制作が好き。