トピックを検索
開いているか伝わらない表示・非表示ボタン
ボタンでパネルを開閉できますが、開閉状態がCSSのクラスにしかないため、支援技術にはどちらの状態でも同じボタンとして伝わります。
class="filter-toggle is-open" 問題
スクリーンリーダーの利用者は、ボタンを押せても、パネルが開いているのか、押して何か変わったのかが分かりません。
商品一覧の上に「フィルター」ボタンがあります。押すと「在庫ありのみ」「セール中」のチェックボックスが並ぶパネルが開き、横の矢印が上向きに変わります。もう一度押すとパネルが閉じます。マウスでもキーボードでも問題なく動きます。スクリーンリーダーの利用者がTabでボタンに移動すると、「フィルター、ボタン」と読み上げられます。Enterを押しても新しい読み上げはなく、もう一度押しても同じです。絞り込みが今開いているのか、移動してきたときにすでに開いていたのか、確かめる方法がありません。
達成基準4.1.2では、利用者が変更できる状態を支援技術が取得でき、変化したときに伝わることを求めています。開閉状態もその一つです。この例では、スクリプトがボタンとパネルの is-open クラスを切り替え、CSSがそのクラスから矢印の向きとパネルの表示を決めています。ボタンには名前と役割がありますが、アクセシビリティツリーには「展開」も「折りたたみ」もありません。変化は描かれても、読み上げられません。
モバイルのメニューボタン、「配送の詳細を表示」のリンク、アイコンの列を出す「その他の操作」ボタンでも、同じ問題が起きます。ボタンでそばの内容を表示したり隠したりする場合は、必ず状態を伝える必要があります。
パネルは、スマートフォンで画面の下に開いたり、拡大している範囲の外に開いたりと、見えない場所に開くことがよくあります。そのとき、何かが起きたことを知る手がかりはボタンの状態だけです。
10グループ中2グループに影響
自動チェックには、名前のあるHTML標準のボタンにしか見えず、何も報告されません。ボタンがパネルを開閉することは分からないため、aria-expanded を求めることもありません。関連するルールの aria-valid-attr-value が反応するのは修正の後で、aria-controls がページにないパネルを指している場合だけです。コード生成のAIは、ラベルを「フィルターを表示」と「フィルターを隠す」で切り替えることがよくあります。これは状態を伝えるのではなく、名前を変えているだけです。また、aria-expanded をマークアップに一度書いて、更新しないこともあります。実際に開閉して、読み上げを聞いてください。
試してみる
Tabで「フィルター」へ移動し、Enterで開いてください。
下の欄に、スクリーンリーダーの読み上げが出ます。絞り込みが開いているか分かりますか?
問題あり 修正できますか?
スクリーンリーダーの読み上げ:
(Tabで「フィルター」へ移動)再現デモです。「問題あり」は意図的にアクセシブルでない状態にしています。
修正方法
ボタンのaria-expandedか、detailsとsummaryで開閉状態を伝えます。
- 1開閉するたびに、状態をパネルの表示と一致させる。
- 2ボタンには表示する内容の名前を付け、名前は変えない。
- 3パネルはボタンの直後に置き、閉じたら届かないようにする。
<button type="button" class="filter-toggle"> フィルター <svg class="chevron" aria-hidden="true">…</svg></button><div class="filter-panel"> <label><input type="checkbox" name="stock"> 在庫ありのみ</label> <label><input type="checkbox" name="sale"> セール中</label></div>今あるボタンにaria-expanded
<button type="button" class="filter-toggle" aria-expanded="false" aria-controls="filters"> フィルター <svg class="chevron" aria-hidden="true">…</svg></button><div class="filter-panel" id="filters" hidden> <label><input type="checkbox" name="stock"> 在庫ありのみ</label> <label><input type="checkbox" name="sale"> セール中</label></div>この方法を選ぶ理由:クラスではなく状態から見た目を決める
ボタンには移動でき、閉じたパネルも正しく隠れていますが、開閉状態はクラスにしかありません。スクリーンリーダーはどちらの状態でも「フィルター、ボタン」と読み上げ、パネルが開いても何も伝えません。
ボタンは「フィルター、ボタン、折りたたみ」と読み上げられ、押すと「展開」と伝わります。矢印も同じ属性から描くため、見た目と読み上げが食い違うことはなく、属性を付け忘れると矢印が動かないので気づけます。hidden 属性を付けると、閉じたパネルはTab順からも、スクリーンリーダーが読む範囲からも外れます。ただし、これはCSSでパネルに display を指定していない場合に限ります。指定している場合は、.filter-panel[hidden] { display: none; } を追加してください。
どちらの方法でも適合します。開閉のボタンがすでにある場合は、aria-expanded を付けるほうが小さな変更で済みます。属性二つ、スクリプト一行、セレクター一つで、パネルもレイアウト上の今の場所に置いたままにできます。その代わり、閉じるボタンや画面遷移も含め、パネルを開閉するすべての処理で属性を更新しなければなりません。details と summary はスクリプトも、そろえ続ける状態も不要です。新しく作る場合で、パネルを同じ要素の中、操作部品の直後に置けるなら、こちらを選びます。ボタンがツールバーにあり、パネルがその下に全幅で広がる場合や、パネルを動きとともに開きたい場合には合わせにくくなります。
ボタンが伝えるべきことの半分は状態で、もう半分は何を操作するかです。それが伝わるかどうかは、次の判断で決まります。
- ボタンには「フィルター」「配送の詳細」のように、表示する内容の名前を付けます。「表示」「もっと見る」や矢印だけにはしません。名前は変えません。「フィルターを隠す、展開」は同じことを二度言っています。また、状態を付けずにラベルだけを切り替えても、フォーカスがボタンにある間は読み上げられないことがよくあります。
- パネルはDOM上でボタンの直後に置きます。
aria-controlsを利用するスクリーンリーダーは少なく、実際に両者を結び付けるのは読み上げの順序です。パネルがページの最後にあると、利用者は何が開いたのかを探すことになります。 - 閉じている間も、パネルをページに残します。フレームワークが開いている間だけパネルを描画すると、閉じたときに
aria-controlsの参照先がなくなり、axeがaria-valid-attr-valueを報告します。hiddenで描画しておくか、パネルがある間だけaria-controlsを付けます。 - メニューにはしません。開閉要素はボタンとパネルです。
role="menu"やaria-haspopupを付けると、パネルにない矢印キーの操作を約束することになります。
スクリプトなしでもページが使えるようにしている場合は、aria-expanded と hidden を起動時にスクリプトで設定します。スクリプトが読み込めなくても、パネルは開いたまま使えます。矢印は currentColor で描き、強制配色でも見えるようにします。
AI コーディングアシスタントで修正しますか? このガイドを Markdown で取得
修正の確認
マウスを使わない5つの確認
確認方法: キーボード、スクリーンリーダー、ズーム、強制配色
OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。共通の開閉コンポーネントを変更した際は、再度確認します。
制限
このサンプルは、どのアプリケーションでも同じ結果になることを保証するものではありません。summary の読み上げ方はスクリーンリーダーによって異なり、ボタンではなく開閉の三角として伝えるものもあります。スクリプトは、アニメーションやパネル内の閉じるボタンを含まない最小限の例です。実際に使用する支援技術で、絞り込みの操作全体を確認してください。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
コードを更新しても、使いやすさを保つために
ガイドの内容を、コーディングエージェントやCIで使える開発ルールにまとめます。更新後は、キーボードとスクリーンリーダーで再テストし、問題が再発していないか確認します。