トピックを検索
チェックマークが読み上げられず空欄と同じになってしまう比較表
料金プランの比較表で機能の有無を aria-hidden の付いたチェックと×印だけで示しているため、「あり」のセルも空のセルと同じになってしまう
<svg aria-hidden="true"> 問題
チェックのセルも×印のセルも空のセルも読み上げに違いがなく、スクリーンリーダーの利用者には、どのプランにその機能があるのか分からない
料金ページで、3つのプランを表で比べています。上にプラン名、左に機能が並び、各セルには小さなアイコンが1つあります。プランに含まれる機能には緑のチェック、含まれない機能にはグレーの×印です。見える人は「シングルサインオン」の行に目を走らせるだけで、Businessにしかないと分かります。スクリーンリーダーの利用者も同じ行をたどります。見出しのマークアップは正しいので、セルごとにプランと機能は分かります。「Starter、シングルサインオン」「Team、シングルサインオン」「Business、シングルサインオン」です。ところが、肝心の値がどのセルにもありません。読み上げる内容のないセルで何と言うかはスクリーンリーダーによりますが、3つとも同じになります。そのため、この表で一番知りたいはずの「どのプランにその機能があるのか」が分かりません。よくあるもう1つの作り方では、チェックだけを描き、「なし」は空のセルにします。チェックが隠れていると、「あり」のセルと「なし」のセルの区別が付きません。
アイコンはアイコンライブラリーから読み込んでいますが、ライブラリーによっては、指定しない限りアイコンを隠します。LucideのコンポーネントとHeroiconsのReactコンポーネントは aria-hidden="true" を出力し、Font AwesomeのKitやSVG + JSのSVGアイコンも同じです。同じ内容の言葉が隣にあるアイコンなら、それで問題ありません。ところがここのテンプレートには <Check /> としか書かれていないので、属性はソースを見ても分からず、セルに言葉もありません。Chromiumのアクセシビリティツリーでは、このセルには名前も子要素もなく、<td></td> とまったく同じです。
この表のチェックは飾りではなく、セルの値そのものです。1.1.1 非テキストコンテンツは、同じ目的を果たす代替テキストを求めており、支援技術に無視させてよいのは、純粋な装飾、見た目の整形のためだけのもの、利用者に提示されないものに限られます。隠されたチェックと×印は情報を伝えているのに、代替テキストがありません。空のセルは事情が違います。非テキストコンテンツがないので1.1.1の対象にならず、チェックにだけ名前を付ける方法でも満たせるのはそのためです。
属性がなくても、同じことが起こります。古いバージョンのLucideは aria-hidden のないSVGを出力し、Chromiumではこれが名前のない画像になります。やはり読み上げる内容はありません。
どこかが壊れているようには聞こえないので、気づきにくい問題です。プラン名と機能名は順番どおりに聞こえ、答えだけが抜けています。必要な機能があるプランを選びたい人は、サイトの別の場所で探すか、問い合わせるしかありません。
10グループ中1グループに影響
- 全盲 (影響あり)
- 弱視 (影響なし)
- 色覚 (影響なし)
- ろう (影響なし)
- 難聴 (影響なし)
- 発話 (影響なし)
- 手の操作 (影響なし)
- 筋力・可動域 (影響なし)
- 認知 (影響なし)
- 光過敏 (影響なし)
- 視覚を使わない スクリーンリーダーや点字の利用者には、各セルのプランと機能は伝わりますが、答えが伝わりません。どのプランでシングルサインオンを使えるのかという、この表で一番知りたいことが分かりません。
axeの svg-img-alt と role-img-alt が見るのは、画像のロールを持つ要素です。このようなセルの表をChromium上のaxe 4.13で調べると、role="img" で名前のないSVGは報告されましたが、同じSVGに aria-hidden="true" を付けたもの、属性のないもの、空のセルは報告されませんでした。飾りのアイコンなら隠すのが正しく、このアイコンが飾りでないことはチェックツールには分かりません。この監査では、名前のないSVGだけを持つセルが2つ以上ある表を、人が確認する項目(ew:table-icon-cells-manual-check)として挙げます。読み上げる内容がないことはコードで分かりますが、印に意味があるかどうかは人が判断するしかないからです。コードを読む人も、レビューを頼まれたAIアシスタントも、見るのは属性のない <Check /> です。aria-hidden は描画後のページにしか現れません。分かるのは、スクリーンリーダーで行をたどったときか、描画されたセルをアクセシビリティツリーで見たときです。
試してみる
Tabキーでセルを順に移動し、見えている内容と読み上げを比べてみましょう
問題1: Tabキーを押すたびに、スクリーンリーダーで次のセルへ移ったときの内容を表示します。チェックにも×印にも、読み上げる内容がありません。
問題2: ×印をなくし、そのセルは空にしています。チェックのセルも空のセルも、同じように読み上げる内容がありません。
修正を適用します。 「シングルサインオン」の行をたどると、「チェックにだけ名前を付ける」では読み上げる内容のないセルが残ります。
問題あり 修正できますか?
| 機能 | Starter | Team | Business |
|---|---|---|---|
| プロジェクト数無制限 | |||
| 共有フォルダー | |||
| シングルサインオン |
スクリーンリーダーの読み上げ:
(Tabでセルへ移動)
修正方法
印のセルにも空のセルにも言葉を入れる
アイコンライブラリーに隠されたチェックと×印
<table class="plans"> <thead> <tr> <th scope="col">機能</th> <th scope="col">Starter</th> <th scope="col">Team</th> <th scope="col">Business</th> </tr> </thead> <tbody> <tr> <th scope="row">共有フォルダー</th> <td> <svg class="no" aria-hidden="true" viewBox="0 0 24 24">…</svg> </td> <td> <svg class="yes" aria-hidden="true" viewBox="0 0 24 24">…</svg> </td> <td> <svg class="yes" aria-hidden="true" viewBox="0 0 24 24">…</svg> </td> </tr> … </tbody></table>問題点2点
見出しは正しく、各セルにプランと機能が対応しています。問題は各セルの中身です。
- チェックは支援技術から隠され、セルにはほかに何もないため、「あり」が伝わりません。
- ×印も隠されているため「なし」も伝わらず、2つのセルが同じになります。
各セルに隠したテキストを入れる
<table class="plans"> <thead> <tr> <th scope="col">機能</th> <th scope="col">Starter</th> <th scope="col">Team</th> <th scope="col">Business</th> </tr> </thead> <tbody> <tr> <th scope="row">共有フォルダー</th> <td> <svg class="no" aria-hidden="true" viewBox="0 0 24 24">…</svg> <span class="visually-hidden">なし</span> </td> <td> <svg class="yes" aria-hidden="true" viewBox="0 0 24 24">…</svg> <span class="visually-hidden">あり</span> </td> <td> <svg class="yes" aria-hidden="true" viewBox="0 0 24 24">…</svg> <span class="visually-hidden">あり</span> </td> </tr> … </tbody></table>修正の手順3ステップ
- アイコンはライブラリーの出力どおり、隠したままにします。値は言葉で伝わるので、アイコンは読まれなくてかまいません。
- 各セルに、値を言葉で書いた「あり」か「なし」の
spanを足し、CSSで見えなくします。この言葉がセルのテキストになり、スクリーンリーダーで表を読むときにも、ブラウザーでページを翻訳するときにも使われます。 - 空のセルがある表では、空のセルにも同じように「なし」を入れます。画面上は空のままで、「なし」と伝わるようになります。
どちらの修正前も直り、1.1.1を満たします。表の見た目は変わりません。画面上の値は印か空欄のままなので、チェックを「あり」と受け取らない人は、推測するしかありません。
この方法を選ぶ理由:まずHTMLの要素を使う
最初の3つは、どれもすべてのセルに値を入れるので、1.1.1を満たし、「なし」も「あり」と同じようにはっきり伝わります。隠したテキストと印の名前は、どちらも今の見た目を保ちます。隠したテキストは普通のテキストなのでARIAが要らず、テキストを扱うものなら何にでも届きます。印に名前を付ける方法では、印は画像として扱われます。aria-label を訳さないページ翻訳ツールもあり、印のないセルには使えません。そのため、見た目を保つなら隠したテキストを使います。見える言葉は行に場所を取りますが、表を見られる人にも役立つので、場所があるときや、チェックを「あり」と受け取らない人がいそうなときに選びます。チェックにだけ名前を付ける方法は、すでにそう作られた表の第一歩としては十分ですが、「なし」が言葉になっていないので、できるときに言葉を足してください。
セルのコンポーネントを1つにする。 値を受け取り、印と言葉を一緒に書き出す1つのコンポーネントからセルを描きます。そうすれば片方だけのセルができず、チェックに違う言葉が付くこともありません。言葉はページのほかの部分と一緒に翻訳します。
ライブラリーのアイコンに名前を付ける。 ライブラリーによって動きが違うので、テンプレートではなく描画後のページで確認します。Lucideは aria-label、role、title のいずれかを渡すと aria-hidden を外します。HeroiconsのReactコンポーネントは、title を渡しても、そのプロパティを上書きしない限り aria-hidden="true" を残すため、ラベルを渡すだけではアイコンは隠れたままです。
「あり」「なし」以外の値があるセル。 「5人まで」「オプション」のような値はもともとテキストなので、何も要りません。注記の付いた印は、注記の内容も言葉に入れます。「あり、年払いのみ」のようにします。
機能リストの印も同じ。 料金カードでは、含まれる機能にチェック、含まれない機能に×印や取り消し線を付けて並べることがよくあり、スマートフォンではこの形のカードに変わる表もあります。印が隠れていると、空欄より悪い結果になります。リストは普通のテキストとして読まれ、すべての機能が使えるように聞こえるからです。直し方は同じで、含まれない機能の項目それぞれに、言葉で「なし」と入れます。
チェックがどこでも「あり」を意味するとは限らない。 W3Cの講演資料には、日本などではチェックマークが「誤り」を示すことがあり、日本向けのローカライズでは ○ に置き換えることが多いと書かれています。見える言葉なら、どこで売っていても迷いません。SVGではなく文字のチェックや×については、意味ではなく名前で読み上げられる絵文字で扱っています。
コントラスト。 値を伝える印には、1.4.11により背景との3:1のコントラストが必要です。薄いグレーの×印は足りないことがあります。コントラストが足りない入力欄・アイコン・フォーカス枠を参照してください。
デザインの案
比較表は、軽い見た目のまま「あり」と「なし」を伝えられる
どのプランにどの機能があるかを6通りに描きました。4つは見た目にかかわらずスクリーンリーダーが読める言葉で伝え、2つは目で見ることに頼っています。
デザインファイルで
- セルの種類ごとの言葉を、印だけを描く場合でもデザインファイルに書く(「あり」「なし」など)。
- 「なし」のセルは空欄にせず、読めるものを入れる。
- 値を伝える印のコントラスト比を横に書く(3:1以上)。言葉は4.5:1以上にする。
- スマートフォンの幅でも表を描き、列が狭くなったときに言葉をどこに置くかを示す。
合格
機能 Starter Team Business シングルサインオン なし なし あり 言葉を入れた淡いピル 「あり」は淡い緑のピルに入れ(7.74:1)、「なし」は灰色の文字にします(白に対して7.56:1)。色でも一覧できるうえ、色や印が見えなくても言葉で伝わります。印より幅をとるので、言葉は短くします。機能 Starter Team Business メンバー 5人 50人 無制限 シングルサインオン なし なし あり セルに値そのものを書く 「5人」「50人」「無制限」は、チェックを3つ並べるより多くを伝え、もともとテキストなので名前を付ける必要もありません。上限のある機能に向いています。「なし」も空欄にせず、言葉で書きます。機能 Starter Team Business シングルサインオン なし なし あり 塗りつぶしのバッジと、枠だけのダッシュ 印の軽い見た目を残します。チェックは緑の円に白で(#1e7b34と白で5.33:1)、ダッシュは細い枠線の中に描きます。色だけでなく形と太さでも違いが分かり、各セルには、画面には出さずにスクリーンリーダーが読む言葉も入れます。Team
あり
- 共有フォルダー
なし
- シングルサインオン
プランごとの2つのリスト 表にせず、プランごとに「あり」と「なし」の見出しの下に機能を並べます。言葉は見出しで一度示すだけで、各行に印は要りません。スマートフォンに向いていますが、プランを横に並べて比べにくくなります。
不合格
機能 Starter Team Business シングルサインオン 緑と赤のドットWCAG 1.1.1 整って見え、見える人にはすぐ読み取れます。しかしドットには言葉がないのでセルに読むものがなく、2色のコントラスト比も1.24:1しかないため、色の違いだけで区別することになります。Team
- 共有フォルダー
- シングルサインオン
含まれない機能を薄くするWCAG 1.4.3 料金カードでよく見る形で、プランにない機能を薄い灰色にします(白に対して1.87:1)。読みやすいとはいえない薄さです。さらに薄さだけが手がかりなので、スクリーンリーダーは含まれる機能と同じように読みます。
修正の確認
4項目、マウス不要
確認方法: スクリーンリーダー、拡大表示
OS、ブラウザー、支援技術のバージョン、ビルド、日付、各手順の実際の結果を記録してください。アイコンライブラリーやそのバージョン、共有しているセルのコンポーネントが変わるたびに繰り返します。
制限
このサンプルは、どの表でも同じ結果になることを保証するものではありません。空のセルで何と言うか、セルの中の画像をどう読むかはスクリーンリーダーによって違うので、利用者が使う支援技術で確認してください。セルの言葉が役に立つのは、セルに見出しもあるときだけです。「あり」と読まれても、プランと機能が分からなければ意味がありません。div で描いた比較表や、見出しを太字にしただけの比較表はそこで問題になります。見出しが太字だけのデータ表を参照してください。表の外のアイコンに名前を付けることと飾りのアイコンを隠すことは名前がない、または読まれてしまうSVGアイコン、ボタンの中のアイコンは名前がないアイコンだけのボタンで扱っています。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
EaseWebのサービス
修正した問題を、次のリリースで再発させない
このガイドのような修正方法を、コーディングエージェントが従うルールと、CIのチェックに組み込みます。あわせて定期的に、キーボードとスクリーンリーダーで手動の再テストを行います。