トピックを検索
キーボードで選べず、読み上げもされない座席表
座席がクリックにしか反応しない空のdivか名前のないボタンで、空席・選択中・予約済みの違いも色だけで示している
<div class="seat taken"></div> 問題
キーボード利用者は座席を選べず、スクリーンリーダー利用者にはどれがどの座席か、空いているかが分からず、赤と緑を見分けにくい人には空席と予約済みの区別がつかない
ある映画館の予約ページでは、1回の上映の座席を座席表で示しています。「スクリーン」と書かれた帯の下に、AからDの4列、各列6席が並びます。空席は緑、予約済みは赤で、空席をクリックすると選択中を示す青に変わります。座席表の上には3つの色を説明する凡例があり、A〜B列は$10、C〜D列は$14と書かれています。マウスなら、C列で隣り合う2席を選ぶのは2回のクリックで済みます。
マウスを使わずにTabキーを押すと、フォーカスはページの先頭からすべての座席を飛ばし、「次へ」へ進みます。座席は一つも選べません。座席が空のdivなので、スクリーンリーダーでページを読んでも、「スクリーン」に続いて列の文字「A」「B」「C」「D」が読まれるだけで、その間には何も聞こえません。赤と緑が同じ色に見える人には、どの座席も同じように見えます。C列の空席の1、2、5、6番は、予約済みの3、4番と同じ色合いです。
そこで、チームは各座席をボタンにします。Tabは各座席に止まるようになりますが、スクリーンリーダーには24席のどれも「ボタン」としか聞こえず、どの列の何番か、料金はいくらかは伝わりません。予約済みの座席もほかと同じボタンで、押しても何も起きず、何も読まれません。座席を選んでも色が変わるだけで、スクリーンリーダーは前と同じように「ボタン」と読みます。
達成基準2.1.1「キーボード」は、マウスでできることはすべてキーボードでもできることを求めています。この座席表で座席を選ぶ方法は、divのクリックだけです。divはフォーカスを受けず、キーにも反応しないため、ポインターなしでは座席を選べません。
達成基準4.1.2「名前(name)・役割(role)及び値(value)」は、どのコントロールにも名前と役割があり、状態が支援技術に伝わることを求めています。座席もコントロールです。選択でき、空席・予約済み・選択中のいずれかの状態を持ちます。divには役割も名前もないため、スクリーンリーダーは何もないかのように通り過ぎます。ボタンには役割があっても、テキストも名前もありません。どちらの場合も、状態を表すのは taken と chosen というクラスと、その色だけです。ブラウザーが支援技術に伝える情報は要素と属性から作られ、クラス名や背景色からは作られないため、状態は伝わりません。
達成基準1.4.1「色の使用」は、色だけで情報を示さないことを求めています。どの座席も、空席か、予約済みか、選択中かを塗りの色だけで示しており、印も形も言葉もありません。座席表の上の凡例には言葉がありますが、凡例と座席を結び付けるのは色だけです。緑、赤、青の明るさの差は1.46:1以内、赤と青では1.11:1しかないため、色味を除くとほとんど同じに見えます。また、色覚特性の中でも多い、赤と緑を見分けにくいタイプの人には、緑と赤がほぼ同じ色に見えます。
映画館、劇場、コンサートホール、スタジアム、航空会社、鉄道は、チケットを買う途中にこのような座席表を置いています。座席表でしか選べない場合、選べない座席は買えないチケットと同じです。座席表の横に「おまかせで選ぶ」ボタンを置くサイトもありますが、選ぶのはサイトの側です。通路側の席も、一緒に来た人の隣も、いつも座る列も選べません。
10グループ中4グループに影響
- 全盲 (影響あり)
- 弱視 (影響あり)
- 色覚 (影響あり)
- ろう (影響なし)
- 難聴 (影響なし)
- 発話 (影響なし)
- 手の操作 (影響あり)
- 筋力・可動域 (影響なし)
- 認知 (影響なし)
- 光過敏 (影響なし)
- 視覚を使わない 座席が空のdivなら、スクリーンリーダー利用者には「スクリーン」という言葉と列の文字だけが読まれ、その間には何も聞こえません。座席がボタンなら、どれも「ボタン」としか読まれません。どの座席も、どの列の何番か、料金はいくらか、空いているか、予約済みか、選択中かを伝えないため、手助けなしでは座席を予約できません。
- 手の操作が限られる 座席がクリックにしか反応しない場合、キーボードやスイッチの利用者はまったく座席を選べません。Tabはページの先頭から座席表全体を飛ばして「次へ」へ進みます。
- 色を知覚しない 赤と緑を見分けにくい人には、空席と予約済みの座席が同じ色に見え、クリックしても何も起きないことで初めて予約済みだと分かります。色味をまったく除くと、3つの色はほとんど同じ濃さです。
- 視覚が限られる 塗りの色を置き換えるWindowsのコントラスト テーマでは、どの座席も同じように描かれます。また、視力の低い人は色の見え方も弱いことが多く、空席・予約済み・選択中を見分けにくくなります。
空のdivには役割がないため、1つ目の座席表ではaxeが確認するものはありません。axeのコントラストのルールが見るのはテキストで、塗りの色が何を意味するかは見ません。2つ目の座席表の空のボタンは、テキストも名前もないため、axeが button-name として報告します。ただし、そのボタンが座席であることや、クラスでは予約済みや選択中と示しているのにマークアップでは何も伝えていないことは分かりません。
この診断ツールは、seat やそれに類するよくあるクラス名を手がかりに、div、span、SVGの図形で作られた座席を探します。Tabが座席にも座席表の中のほかの要素にも届かない座席表を報告し、Tabは届いても、クラスでは予約済みや選択中と示しているのに disabled、aria-disabled、checked、aria-pressed、aria-checked、aria-selected のどれも持たない座席も報告します。Tabが届く座席表は、人が確認する項目として渡し、各座席の名前が列と番号を伝えているか、色がなくても状態が分かるかを確かめてもらいます。idやクラス名で座席表と分かる canvas も、同じように確認に回します。それと分かるクラス名のない図形で作った座席表は見つからず、座席の名前が聞く人にとって分かりやすいかは、どの確認でも分かりません。
広く写されている座席予約のチュートリアルは、1つ目の作り方、つまり1席ごとに空のdivを置き、座席表全体に1つのクリック処理を付ける形で作られています。AIアシスタントに座席表をアクセシブルにするよう頼むと、divをボタンに変えただけで終わり、2つ目の座席表になることがあります。すべての座席に aria-label="座席" のような同じ名前を付けることもあります。
試してみる
キーボードだけで、C列の隣り合う空席を2つ選んでみましょう
問題1: Tabキーを押します。フォーカスはすべての座席を飛ばして「次へ」へ進み、どの座席も読まれません。シミュレーションをオンにすると、空席と予約済みが同じように見えます。
問題2: 同じ座席をボタンにしただけです。Tabは各座席に止まりますが、どの座席も「ボタン」としか読まれず、選んでも色が変わるだけです。
修正を適用します。 チェックボックスでは、Tabで空席を順に移動し、Spaceキーで選べます。グリッドでは、Tabを1回押すと座席表に入り、矢印キーで座席と列の間を移動できます。
問題あり 修正できますか?
座席を選択
A〜B列 $10・C〜D列 $14
- 空席
- 選択中
- 予約済み
スクリーンリーダーの読み上げ:
(Tabで座席へ移動)
修正方法
座席に名前を付け、キーボードで選べるようにし、状態に印を付ける
クリックに反応するdivの座席
<h2>座席を選択</h2><p>A〜B列 $10・C〜D列 $14</p><ul class="legend"> <li> <span class="key"></span> 空席 </li> <li> <span class="key chosen"></span> 選択中 </li> <li> <span class="key taken"></span> 予約済み </li></ul><div class="seat-map"> <div class="screen">スクリーン</div> … <div class="row"> <span class="row-name">C</span> <div class="seat"></div> <div class="seat"></div> <div class="seat taken"></div> <div class="seat taken"></div> <div class="seat"></div> <div class="seat"></div> </div> …</div><button type="button" class="continue">次へ</button>問題点4点
- 座席は
clickにしか反応せず、フォーカスも受けないため、Tabは座席表を飛ばし、キーボードではどの座席も選べません。 - 座席は空のdivのため、スクリーンリーダーは列の文字を読むだけで、その間には何も読みません。
- 空席・予約済み・選択中の区別はクラスだけで、支援技術には伝わりません。
- 画面上でも、違いは塗りの色だけです。
座席ごとのチェックボックス
<h2>座席を選択</h2><p>A〜B列 $10・C〜D列 $14</p><ul class="legend"> <li> <span class="key"></span> 空席 </li> <li> <span class="key chosen"></span> 選択中 </li> <li> <span class="key taken"></span> 予約済み </li></ul><div class="seat-map"> <div class="screen">スクリーン</div> … <div class="row"> <span class="row-name">C</span> <label class="seat"> <input type="checkbox" name="seats" value="C1"> <span class="visually-hidden">C列1番、$14</span> </label> <label class="seat"> <input type="checkbox" name="seats" value="C2"> <span class="visually-hidden">C列2番、$14</span> </label> <label class="seat"> <input type="checkbox" name="seats" value="C3" disabled> <span class="visually-hidden">C列3番、$14</span> </label> <label class="seat"> <input type="checkbox" name="seats" value="C4" disabled> <span class="visually-hidden">C列4番、$14</span> </label> <label class="seat"> <input type="checkbox" name="seats" value="C5"> <span class="visually-hidden">C列5番、$14</span> </label> <label class="seat"> <input type="checkbox" name="seats" value="C6"> <span class="visually-hidden">C列6番、$14</span> </label> </div> …</div><button type="button" class="continue">次へ</button>修正の手順5ステップ
- 各座席をlabelの中のチェックボックスにし、列、番号、料金を伝える隠したテキストを付けます。Tabが止まり、Spaceキーで選べ、スクリーンリーダーは「C列5番、$14、チェックボックス、チェックなし」と読み上げます。
- 予約済みの座席のチェックボックスは無効にします。Tabキーでは飛ばされますが、スクリーンリーダーで座席表を読み進めると「使用不可」や「淡色表示」と読み上げられます。
appearance: noneでチェックボックスそのものに座席を描き、色は:checkedと:disabledから付けます。見た目と読み上げが食い違うことはありません。- 座席にも凡例にも、選択中にはチェック、予約済みには×を描きます。枠線で描くため、Windowsのコントラスト テーマでも消えません。
- スクリプトは削除します。状態はチェックボックス自身が持ち、フォームの中に置けば、選んだ座席の値はコードなしで送信されます。
これで二つの修正前の例はどちらも直り、達成基準1.4.1、2.1.1、4.1.2を満たします。空席はすべてTabの移動先になり、列ごとに読む順にたどれます。
この方法を選ぶ理由:まずHTMLの要素を使う
どちらも基準を満たします。この映画館のスクリーンのような小さな会場には、チェックボックスを使ってください。スクリプトがなく、壊れるところもありません。フォームの中に置けば、JavaScriptを読み込む前でも選んだ座席が送られます。利用者は、ほかのフォームと同じように、Tabで列ごとに空席を順に移動します。劇場、航空機、スタジアムの一区画のような大きな会場には、グリッドを使ってください。何百もの座席をTabで移動していては何分もかかり、利用者は後ろの列へそのまま移れることを期待します。その代わり、すべてのキーを扱うスクリプトが必要で、グリッドへの対応はスクリーンリーダーによって違うため、それぞれでの確認も必要です。
座席の名前は、フォーカスが移るたびにそれだけで読まれます。「5番」や「5」だけでは、フォーカスが1つ下の列へ移ったときに足りないため、どの名前にも列を入れます。選ぶときに大事な情報は、「通路側」「見えにくい席」「車いす用スペース」「足元が広い席」のように番号の後に加え、料金は座席によって違う場合にだけ入れます。車いす用スペースのように、座席ではない場所も同じで、その場所が何かを名前にします。
2つ目の修正前のように座席がすでにボタンなら、いちばん小さな変更はボタンのまま直すことです。各座席に隠したテキストと aria-pressed を付け、予約済みの座席に disabled を付けて、見た目をそれらの属性から描きます。チェックボックスの方法をボタンに置き換えたもので、空席はどれもTabの移動先になり、スクリーンリーダーは「チェックボックス」ではなく「トグルボタン」と読みます。
大きな会場では、まず区画の地図を示し、選んだ区画の座席を次に示すことがよくあります。各区画にも座席と同じ扱いが必要です。キーボードで届くコントロールにし、区画名と料金帯で名前を付け、「売り切れ」は灰色だけでなく言葉でも伝えます。拡大やドラッグで動かせる座席表には、どちらの操作にもボタンが必要です。ボタンで代われないピンチ・ドラッグ・傾きのジェスチャーを参照してください。canvas に描いた座席表は、スクリーンリーダーに何も伝えません。その上に座席を要素として描くか、横に空席の一覧を列ごとに置きます。
座席そのものにも、周りとの3:1のコントラストが必要です。コントラストが足りない入力欄・アイコン・フォーカス枠を参照してください。この例では、緑は白に対して3.45:1で、赤と青はそれより高くなっています。印は赤と青の上の白で、4.51:1と5.02:1です。チェックと×は枠線で描いているため、塗りの色を取り除くWindowsのコントラスト テーマでも見えます。背景のグラデーションで描いた印は、そこで消えてしまいます。注文のステータスのように、ほかの場所で色だけが状態を示している場合は、色だけで区別されるステータス表示を参照してください。
多くのサイトは、「次へ」の横に選んだ座席と合計を「C列5番・6番、$28」のように示します。この行は、支払いの前に誰もが選んだ内容を確かめるのに役立ちます。ただし、読み上げで知らせない限り、スクリーンリーダーにはそこまで読み進めたときにしか聞こえません。バッジしか変わらない「カートに入れる」ボタンを参照してください。
修正の確認
5項目、マウス不要
確認方法: キーボード、スクリーンリーダー、色覚シミュレーション、強制配色
OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。座席表、その部品、ライブラリーを変更した際は、再度確認します。
スクリーンリーダーでの aria-pressed、role="grid", a button in each cellの読まれ方
制限
このサンプルは、どのアプリケーションでも同じ結果になることを保証するものではありません。グリッドのスクリプトは最小限の例で、Page UpとPage Downや、列の文字で列へ移動する方法はありません。大きな会場では、それらが必要になることがあります。NVDAでは、グリッドのセルの中のリンクへ矢印キーで移動するとフォーカスモードが解除され、矢印キーが読み上げのカーソルを動かすようになると報告されています。このボタンでも同じことが起きると、NVDAの利用者はInsert + Spaceで矢印キーを取り戻す必要があるため、特にNVDAでグリッドを確かめてください。映画館の一覧のように、会場を街の地図に示すものは、場所が地図でしか分からない店舗マップで扱っています。セルを選ぶのではなく編集するグリッドはキーボードでセルを移動・編集できないデータグリッドで、フォームの中の手作りのチェックボックスはキーボードでもスクリーンリーダーでも使えないカスタムチェックボックスで扱っています。上映を選んでから支払うまでの一連の操作全体を、対象とする支援技術でテストしてください。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
EaseWebのサービス
修正した問題を、次のリリースで再発させない
このガイドのような修正方法を、コーディングエージェントが従うルールと、CIのチェックに組み込みます。あわせて定期的に、キーボードとスクリーンリーダーで手動の再テストを行います。