トピックを検索
画面に見えるのにスクリーンリーダーが読まないテキスト
店が「売り切れ」のバッジを商品写真のリンクの中に描き、そのリンクを重複としてスクリーンリーダーから隠しているため、どのマグが売り切れなのかをスクリーンリーダーは読み上げません。
<a class="photo" href="/mugs/glazed" aria-hidden="true" tabindex="-1"> 問題
スクリーンリーダーの利用者には、どの商品が売り切れなのかが伝わらず、商品を開いて初めて分かります。
マグの店が、商品をカードの一覧で並べています。カードには写真、リンクになったマグの名前、価格があります。売り切れたマグには、買い物客が最初に見る写真の上に「売り切れ」のバッジを描きます。写真は名前と同じページへのリンクなので、よく勧められるとおり、スクリーンリーダーから隠してTabの移動先からも外し、カードごとのリンクを一つにしています。バッジは、その写真のリンクの中にあります。
画面では、「釉薬のマグ」が売り切れなのは一目で分かります。ところが、スクリーンリーダーで一覧を読むと「斑点模様のマグ、リンク、£18。釉薬のマグ、リンク、£22。背の高いマグ、リンク、£20」となり、釉薬のマグをほかと区別するものがありません。買い物客は商品を開き、商品ページで初めて買えないことを知ります。
達成基準1.3.1「情報及び関係性」は、見た目で示している情報を、コードから判断できるか、テキストで得られるようにすることを求めています。「このマグは売り切れ」というのも情報の一つで、ここではバッジにしか書かれていません。
aria-hidden="true" は、要素とその中身すべてを支援技術に渡す内容から外し、それ以外は何もしません。名前のリンクと重複する写真のリンクには適切です。しかし、中のバッジも同じ扱いになるため、バッジが示す情報は、スクリーンリーダーが受け取るテキストにありません。
この問題に出会うのは、ページを音声や点字で受け取る人すべてです。目で見て確かめるだけでは気づけません。画面を見ながらマウスやキーボードで操作する人は、この問題に出会いません。
10グループ中2グループに影響
axeには、aria-hidden の中の見えるテキストを調べるルールがありません。aria-hidden-focus が調べるのはフォーカスを受けるものだけで、バッジは受けません。隠した内容が必要かどうかは人にしか判断できないため、この診断では、aria-hidden の中の見える言葉を確認に回します(ew:aria-hidden-text-manual-check)。ただし、記号、アイコンの字形、同じカードでもう一度読まれる言葉は除きます。透明にしたり画面の外に移したりしたのに読まれるテキストは、まったく報告しません。視覚的に隠したテキストは、画面にない言葉をスクリーンリーダーに渡す正当な方法でもあり、意図して隠した言葉と紛れ込んだ言葉をコードでは区別できないからです。body要素の aria-hidden はaxeの aria-hidden-body として報告し、role="presentation" を付けたデータテーブルは確認に回します(ANDI)。AIアシスタントに「重複している画像のリンクをスクリーンリーダーから隠して」と頼むと、中にほかに何があるかを見ずに、リンクに aria-hidden を加えることがあります。
修正方法
状態は画面とスクリーンリーダーが共有する言葉で伝え、当てはまらないものは全員から隠します。
- 1必要な言葉をaria-hiddenの要素の中に入れない。同じ言葉がそばで読まれる場合を除く。
- 2当てはまらないものは、opacityや画面外への配置ではなく、hiddenかdisplay: noneで全員から隠す。
- 3スクリーンリーダーでページを読み、カードごとに画面と比べる。
<ul class="products"> … <li class="card"> <a class="photo" href="/mugs/glazed" aria-hidden="true" tabindex="-1"> <img src="/img/glazed-mug.jpg" alt=""> <span class="badge">Sold out</span> </a> <a href="/mugs/glazed"> Glazed mug </a> <p class="price">£22</p> </li> <li class="card"> <a class="photo" href="/mugs/tall" aria-hidden="true" tabindex="-1"> <img src="/img/tall-mug.jpg" alt=""> </a> <a href="/mugs/tall">Tall mug</a> <p class="price">£20</p> </li></ul>写真の外のバッジを、売り切れのカードにだけ書く
<ul class="products"> … <li class="card"> <a class="photo" href="/mugs/glazed" aria-hidden="true" tabindex="-1"> <img src="/img/glazed-mug.jpg" alt=""> </a> <span class="badge">Sold out</span> <a href="/mugs/glazed"> Glazed mug </a> <p class="price">£22</p> </li> <li class="card"> <a class="photo" href="/mugs/tall" aria-hidden="true" tabindex="-1"> <img src="/img/tall-mug.jpg" alt=""> </a> <a href="/mugs/tall">Tall mug</a> <p class="price">£20</p> </li></ul>この方法を選ぶ理由:隠すときは、全員から一度に隠す
重複する写真のリンクを隠すのは正しいことですが、バッジも一緒に隠れます。釉薬のマグが売り切れだと伝える言葉は aria-hidden の中にしかないため、スクリーンリーダーは、そのカードを背の高いマグのカードとまったく同じように読みます。
テンプレートは、マグが売り切れのときだけ、写真のリンクの中ではなくその隣にバッジを書き、CSSは引き続き写真の上に描きます。画面に表示されるものとスクリーンリーダーが読むものが同じ要素から生まれ、「売り切れ、釉薬のマグ、リンク、£22」と読まれます。ページを開いている間に在庫が変わる場合は、カードごとにバッジを一つ置き、全員から一度に隠す hidden 属性で切り替えます。opacityは使いません。
どちらも1.3.1を満たし、どちらもバッジを当てはまる場所にだけ書きます。写真の外のバッジは、見えるものと読まれるものが一つの要素なので、二つを揃え続ける手間がありません。マークアップでバッジを動かせるなら、こちらを選びます。リンクに言葉を入れる方法は、マークアップを元のまま保ち、リンクで移動する人に聞こえる場所に状態を置きます。その代わり、同じ言葉を二か所に書くことになり、テンプレートでバッジと揃え続ける必要があります。どちらを選んでも、当てはまらないものは hidden か display: none で隠し、opacityは使いません。
すべてのカードに書いて透明にしたバッジ。 バッジを写真のリンクの外に移すだけでは、修正は半分です。テーマがすべてのカードにバッジを書き、在庫のあるマグでは opacity: 0 で透明にすると、逆の失敗になります。opacityは、透明な文字色や画面の外への配置と同じく、バッジを目から隠すだけでテキストには残すため、画面に表示されるのは一つでも、スクリーンリーダーはすべてのマグの前で「売り切れ」と読みます。バッジは当てはまる場所にだけ書くか、全員から隠す hidden 属性か display: none で隠します。
視覚的に隠したテキストが問題なのではありません。 スクリーンリーダーだけが受け取るテキストは、リンクの「売り切れ」や、ページ番号の前の「ページ」のように、画面の内容を繰り返したり補ったりするなら適切です。問題になるのは、透明にしたバッジのように、画面にないことを伝えるときです。上のような共通のクラスを一つ使い、テキストを画面の遠く外へ移す方法は避けます。レイアウトによっては、ページが横にスクロールしてしまうためです。
aria-hiddenの中にほかに何があるか。 重複する写真のリンクは aria-hidden に向いた場所ですが、写真だけを含む場合に限ります。写真の上に描いた価格、評価、「残り2点」も、バッジと同じ問題を抱えます。aria-hidden の中にフォーカスを受けるものがある場合は別の問題です。Tabで届くのに読み上げられない、aria-hiddenの要素を参照してください。
body要素のaria-hidden。 モーダルやメニューのスクリプトが、body に aria-hidden="true" を付けたまま外し忘れることがあります。現在のChromiumとWebKit(それぞれChromeとSafariのエンジン)、バージョン139以降のFirefoxは、ARIA 1.3の草案が求めるとおり、body要素に付いたaria-hiddenを無視します。ただし、古いブラウザーでは、支援技術からページ全体が隠れることがあります。属性を外し、モーダルの背後のページは inert かHTML標準のダイアログで隠します。背後にフォーカスが残るモーダルを参照してください。
presentationにしたテーブル。 サイズ表のようなデータテーブルに role="presentation" や role="none" を付けると、行、列、見出しが失われ、スクリーンリーダーはセルをただの言葉の並びとして読みます。W3Cが1.3.1の失敗例として挙げるF92にあたります。セルに見出しが必要なテーブルからはロールを外し、レイアウトに使うテーブルにだけ残します。ロールを外したリストには別のガイドがあります。divやアイコン、手入力の番号で作った見た目だけのリストを参照してください。
画像。 飾りだけの画像には、ここの写真のように、aria-hidden ではなく alt="" を付けます。ファイル名や同じ言葉が読まれる装飾画像を参照してください。
AI コーディングアシスタントで修正しますか? このガイドを Markdown で取得、または全ガイドをコーディングエージェントで使う。
修正の確認
マウスを使わない5つの確認
確認方法: スクリーンリーダー
OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。カードのコンポーネント、テーマ、在庫の表示を変更した際は、再度確認します。
制限
このガイドの対象は、表示されているのに読まれない言葉と、読まれるのに表示されていない言葉です。aria-hidden の中のフォーカスを受ける要素はTabで届くのに読み上げられない、aria-hiddenの要素で、装飾画像はファイル名や同じ言葉が読まれる装飾画像で扱います。隠した言葉が必要かどうか、スクリーンリーダー向けに意図して隠したものかどうかは、ページごとに人が判断する必要があります。カードやリンクの読み方はスクリーンリーダーや点字ディスプレイによって違うため、利用者が使う組み合わせで確認してください。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
コードを更新しても、使いやすさを保つために
ガイドの内容を、コーディングエージェントやCIで使える開発ルールにまとめます。更新後は、キーボードとスクリーンリーダーで再テストし、問題が再発していないか確認します。