トピックを検索
キーボードでもスクリーンリーダーでも選べない星評価
レビューのフォームで、クリックした星まで塗られる5つの星を、クリックのハンドラー付きのspanや、display: noneで隠したラジオボタンで作っています。そのためTabは星に届かず、スクリーンリーダーには評価が伝わらず、選んだ評価は塗られた星の見た目にしか表れません。
<span class="star" onclick="rate(4)"> 問題
キーボードやスイッチの利用者は評価を選べず、スクリーンリーダーの利用者には星も、どれを選んだかも伝わらないため、商品を評価することも、付けた評価を確かめることもできません。
あるショップのレビューのフォームには、「総合評価」の下に大きな星が5つ並んでいます。灰色の輪郭だけの星で、クリックするとその星まで琥珀色に塗られます。星なら誰でも読み方を知っていますし、プルダウンや数字の列よりも気軽に意見を求められます。開発者は描かれたとおりに、よくある二つの方法のどちらかで作ります。一つは、各星を span にしてクリックのハンドラーを付け、その星と手前の星を塗る方法。もう一つは、各星をラジオボタンのラベルにし、ラジオボタンを display: none で隠して、チェックされたものから星を塗る方法です。マウスで使う限り、どちらも同じに見えて同じに動きます。4つ目の星をクリックすれば、星が4つ塗られます。
マウスを使わずに、設問からTabを押します。フォーカスは「レビューを投稿」へ直接移り、星には一度も届かず、星を塗れるキーもありません。スクリーンリーダーは「総合評価」、続いて「レビューを投稿、ボタン」と読みます。spanの星は何も読まれません。ラジオボタンを隠した場合は、ラベルに隠した「星1つ」から「星5つ」を5行のただのテキストとして読むだけで、ラジオボタンであることも、どれを選んだかも伝わりません。マウスで4つ目の星をクリックしてから聞き直しても、読み上げは変わりません。評価は、4つ塗られた星という見た目にしかありません。
星は操作部品として描かれていますが、操作部品として作られていません。span にはフォーカスが届かず、役割もなく、クリックのハンドラーを付けてもどちらも加わりません。display: none のラジオボタンはページから完全に取り除かれ、Tabの順序からもアクセシビリティツリーからも外れます。一方で、ラベルをクリックすればチェックは付くので、マウスではこれまでどおり動き、マウスで確かめる人には問題が見えません。
このため、3つの達成基準を満たしていません。2.1.1 キーボード:クリックでは評価を選べますが、フォーカスできるものが残っていないため、どのキーでも選べません。4.1.2 名前・役割・値:目に見えるのは、一つの値を選ぶ5つの選択肢と、そのうちの選ばれた一つです。ところがソフトウェアには、ラジオボタンも、「星4つ」のような名前も、チェックの状態も見つからないため、スクリーンリーダーは星が何なのかも、どれが選ばれているかも伝えられません。1.3.1 情報及び関係性:星の絵は、「総合評価」が星で答える設問であること、5つの星が一つの選択としてまとまっていること、いくつ選んだかを、一度に示しています。spanの場合、コードでは設問はどこにも結び付かない段落で、星はばらばらのspan、選択はそのうち4つに付いたクラスです。ラジオボタンを隠した場合は、fieldsetが星を設問の下にまとめてはいますが、星を一つの選択にし、どれを選んだかを伝えるラジオボタンが取り除かれています。どちらの場合も、選択は画面の上にしかありません。これは、WCAGの失敗例F15(アクセシビリティAPIを通じて支援技術に伝わらない独自の操作部品)にあたります。
評価を付けるのは、何かを終えたときです。購入後のレビュー、サポートのチャットを終えた後の「対応はいかがでしたか?」、講座やレシピの採点などです。マウスでしか付けられないと、レビューは評価なしになり、ショップが集める評価は、クリックやタップができる人のものだけになります。
10グループ中2グループに影響
問題のほとんどは、あるべきものが欠けていることです。axeは表示されているものを調べるので、display: none のラジオボタンは調べません。背景に星を描いた空の span には、確認する役割もありません。ページにあるものを調べても、問題は見つかりません。EaseWebの診断は、どちらの作り方も見つけます。classやidで評価や星を示す要素の中に、それぞれポインターのカーソルを持つ星が並び、どれにもTabが届かないものを ew:rating-star-unreachable として、ラベルは表示されているのに隠れているラジオボタンを、言葉のない星のラベルも含めて ew:hidden-native-input として報告します。作り直した星に名前のない role="radio" を付けると、axeが aria-toggle-field-name を報告します。修正を頼むと、コード生成AIは各spanに tabindex="0" を付けることがあります。Tabは5回止まるようになりますが、どのキーでも選べず、ラジオボタンであることも、どれを選んだかも読み上げられません。各spanに aria-label="星4つ" を付ける手当てもありますが、spanはその名前を持てず、キーボードも使えないままです。マウスを使わずに、評価を付けてみてください。
試してみる
星をクリックしてから、マウスを使わずに、Tabで星へ移動し、矢印キーで星4つを付けてください。
マウスなら、どちらの作り方でも星が塗られます。下の欄に、フォーカスの移動や選択の変化に合わせたスクリーンリーダーの読み上げが出ます。星そのものや、どれを選んだかは読み上げられるでしょうか?「問題2」の星は、本物のラジオボタンをdisplay: noneで消して作っています。
問題あり 修正できますか?
スクリーンリーダーの読み上げ:
(Tabでフォームを移動)
修正方法
星を、設問で名前を付けた一つのラジオボタンのグループとして作り、各星に値で名前を付けます。
- 1星はラジオボタンか、aria-checkedを持つrole="radio"で作り、設問で名前を付けた一つのグループにまとめる。
- 2各星には「星1つ」から「星5つ」のように、値で名前を付ける。
- 3塗られた星とフォーカスの枠は、チェックとフォーカスの状態から描く。
Onclick付きの5つのspan
<form action="/reviews" method="post"> <p class="question">総合評価</p> <div class="stars"> <span class="star" onclick="rate(1)"></span> <span class="star" onclick="rate(2)"></span> <span class="star" onclick="rate(3)"></span> <span class="star" onclick="rate(4)"></span> <span class="star" onclick="rate(5)"></span> </div> <input type="hidden" name="rating"> … <button type="submit">レビューを投稿</button></form>描いた星の上にラジオボタンを重ねる
<form action="/reviews" method="post"> <fieldset class="stars"> <legend class="question">総合評価</legend> <label class="star"> <input type="radio" name="rating" value="1"> <span class="visually-hidden">星1つ</span> </label> <label class="star"> <input type="radio" name="rating" value="2"> <span class="visually-hidden">星2つ</span> </label> <label class="star"> <input type="radio" name="rating" value="3"> <span class="visually-hidden">星3つ</span> </label> <label class="star"> <input type="radio" name="rating" value="4"> <span class="visually-hidden">星4つ</span> </label> <label class="star"> <input type="radio" name="rating" value="5"> <span class="visually-hidden">星5つ</span> </label> </fieldset> … <button type="submit">レビューを投稿</button></form>この方法を選ぶ理由:まずHTMLの要素を使う
spanが受け付けるのはクリックだけです。Tabの順序になく、役割も名前も状態もなく、評価は、支援技術が読まないクラスと隠しフィールドの値にしかありません。
デザインは描かれたとおりに残ります。同じ星、同じ塗りで、画面に増えるのはフォーカスの枠だけです。ラジオボタンは取り除かずに透明にし、それぞれを自分の星の上に重ねるので、Tabの順序にもアクセシビリティツリーにも残り、星に触れればそのラジオボタンに届きます。あとはブラウザーが担います。Tabは評価に一度だけ止まり、矢印キーで選択が星一つずつ移り、スクリーンリーダーは設問の「総合評価」に続けて、「星4つ、ラジオボタン、チェックあり、5分の4」のように読み上げます。設問はグループの legend で、星はチェックされたラジオボタン自体から塗るので、見た目と読み上げがずれません。ラジオボタンはソースでは1から5の順に並び、チェックされた星より前の星は :has() で塗るので、塗りのために順序を逆にする必要もありません。
三つとも適合します。描いた星の上にラジオボタンを重ねる方法は、デザインを描いたとおりに残し、スクリプトも要らず、キー、フォーカス、フォームの値、タッチでの位置をブラウザーに任せられます。星をラベルにできるなら、これを使います。ARIAのラジオグループは、スクリプトやコンポーネントが描く要素を残せますが、キー、フォーカス、状態を自分で書いて確かめることになります。星をラベルにできないときだけ使います。評価を言葉でも星の横に書くかどうかは、デザインで決めることです。フォームに1行加わる代わりに、星を数えられない人、数えたくない人にも評価が伝わります。デスクトップだけでなくスマートフォンでも言葉を置く場所があるか、デザインファイルの上で決めてください。
CSSだけで作る定番の星評価は、ラジオボタンを5から1の順に書き、flex-direction: row-reverse で並びを逆にします。input:checked ~ label で塗れる、チェックされた星より後ろの星を、画面では手前に見せるためです。これはまねしないでください。スクリーンリーダーは「星5つ」から読み、矢印キーは押した矢印と逆の向きに選択を移します。修正のように :has() を使えば、ソースの順序のまま、チェックされた星より前の星を塗れます。
ラジオボタンはチェックを外せません。評価を空のままにできるなら、星の後に「評価を取り消す」ボタンなどの戻り道が必要です。スクリプトでグループのチェックを外し、フォーカスを最初の星へ戻します。評価が必須なら、ラジオボタンに required を付けられます。フォームを送信したとき、ブラウザーがグループへフォーカスを移し、何が足りないかを伝えます。
ポインターを星の上で動かすと、評価をプレビューとして見せるデザインも多くあります。ラジオボタンがあれば、:hover だけで描くこのプレビューは問題になりません。矢印キーは移るたびに星をチェックするので、キーボードの利用者にはプレビューではなく実際の選択が見えます。半分の星を使うなら、半分ごとに一つ、合わせて10個のラジオボタンが必要です。名前は「星半分」から「星5つ」とし、各星を半分ずつ描き分けます。ポインターが星のどちらの半分にあるかをスクリプトで読む方法では、キーボードで半分を選ぶ手段がありません。
Windowsのコントラスト テーマでは、ブラウザーが色を利用者の配色に置き換えますが、背景画像は残すので、星は琥珀色と灰色のまま表示され、輪郭の星と塗られた星を見分けられます。フォーカスの枠は outline で描いており、ブラウザーがテーマの色で描き直します。SVGの fill を固定の色で描いた星は、暗いテーマで背景に溶けることがあります。W3Cの例のように currentColor で描いてください。
ほかの方法で隠したチェックボックスとラジオボタン、そして appearance: none でinput自体に描く方法など、そのほかの修正はキーボードでもスクリーンリーダーでも使えないカスタムチェックボックスで扱います。商品名の横の平均評価のように、付けた後に表示する評価は操作部品ではありません。「5段階中4」のように評価を言葉で伝える必要があります。その方法は読み上げられないことが多い、divやspanのaria-labelで示しています。
AI コーディングアシスタントで修正しますか? このガイドを Markdown で取得、または全ガイドをコーディングエージェントで使う。
デザインの案
キーで選べさえすれば、評価は星でも数字でも顔でも描けます。
評価の描き方を4通り並べました。クリックしてから、マウスを使わずにTabと矢印キーで試してください。3つは適合します。残る1つは、マウスなら半分の星を付けられますが、キーでは付けられません。
デザインファイルで
- デザインファイルに、星は5つの選択肢を持つ一つの設問、つまりラジオボタンのグループだと書き、ラジオボタンで作られるようにする。
- 星の上に設問を書き、各星には、スクリーンリーダーが読み上げる「星1つ」から「星5つ」の名前を付ける。
- Tabで移動し、矢印キーで選択を動かしたときの見た目として、フォーカスの枠が付いた星を描く。
- 何も選んでいないときの評価を描き、一度選んだ後に取り消せるかどうかを書く。
合格
- 両端に言葉を添えた数字の円 1から5の数字を入れた直径40pxの円を5つ並べ、両端の下に「不満」と「とても満足」を添えます。アンケートでよく見る形です。数字がそのまま評価なので、ひと目で、白黒でも読み取れます。選んだ円は#1a1a1aで塗られ、白に対して17.40:1です。
- 選んだ顔の言葉が下に出る表情の列 とても不満からとても満足までの5つの顔に、それぞれの意味で名前を付け、選んだ顔の言葉を列の下に書きます。顔の表情を読み取れなくても伝わります。選んだ顔には淡い琥珀色と、#b45309の輪(白に対して5.02:1)が付きます。
- 控えめな「取り消す」が付く星 空のままでもよい評価には戻り道が必要です。選んだ星は、キーでは選択を外せないからです。星を選ぶと、星の後に#4b5563の下線付きの「取り消す」(7.56:1)が現れ、マウスでもキーボードでも星を空に戻せます。
不合格
- ポインターの位置で決まる半分の星WCAG 2.1.1 4つ目の星の左半分をクリックすると3.5になりますが、Tabと矢印キーでは星1つ単位でしか移れず、半分はどのキーでも付けられません。半分が必要なら選択肢を10個描き、必要でなければ半分の星はやめます。
修正の確認
5つの確認
確認方法: キーボード、スクリーンリーダー、マウス、強制配色、タッチ
OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。評価のコンポーネントやテーマを変更した際は、再度確認します。
制限
このサンプルは、どのアプリケーションでも同じ結果になることを保証するものではありません。CSSは最小限の例なので、星の大きさ、コントラスト、フォーカスの枠を実際の配色で確認してください。同じ形の灰色の星と黄色の星のように、色だけで見分ける星は別の問題で、色だけに頼る表示のトピックで扱います。そのガイドは準備中です。設問が結び付いていないラジオボタンのグループは設問名がないラジオボタンとチェックボックスのグループで扱います。レビューのフォーム全体を、キーボード、スクリーンリーダー、スマートフォンで確認してください。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
参考資料
- WCAG Understanding: keyboard(新しいタブで開きます)
- WCAG Understanding: name-role-value(新しいタブで開きます)
- WCAG Understanding: info-and-relationships(新しいタブで開きます)
- WCAG Technique F15(新しいタブで開きます)
- ARIA APG: radio-rating(新しいタブで開きます)
- ARIA APG: radio(新しいタブで開きます)
- developer.mozilla.org: :has(新しいタブで開きます)
- developer.mozilla.org: fieldset(新しいタブで開きます)
コードを更新しても、使いやすさを保つために
ガイドの内容を、コーディングエージェントやCIで使える開発ルールにまとめます。更新後は、キーボードとスクリーンリーダーで再テストし、問題が再発していないか確認します。