アクセシブルなJavaScriptアコーディオンとタブ
JavaScriptのアコーディオンとタブ
アクセシブルなJavaScriptアコーディオンとタブ:コピペで使えるコード | We.Inc
高さのアニメーションとaria-expandedを備えた素のJavaScriptのアコーディオンと、矢印キーとロービングtabindexで操作できるタブ。どちらもページ上でライブ動作し、キーボードのチェックリストとARIAの表も掲載しています。
アクセシブルなアコーディオンでは、各見出しの中に本物のボタンを置き、aria-expandedでパネルが開いているかを示し、aria-controlsでパネルを指定します。アクセシブルなタブでは、role=tablist、tab、tabpanelとaria-selectedを使い、矢印キーでタブ間を移動し、選択中のタブだけをTabキーの移動順に含めます。下の2つのデモはどちらもライブで動作します。
どちらを使うか
- アコーディオン
- 質問が並ぶ長いページで、複数の回答を読む可能性がある場合
- details要素とsummary要素
- JavaScriptをまったく使わない、シンプルな表示と非表示
各デモは、HTML、CSS、JavaScriptがひとまとまりになった独立したブロックです。編集すると結果が再実行されます。その後はマウスから手を離し、下にあるチェックリストを使ってキーボードでテストしましょう。
- 必要なコンポーネントのブロックを自分のページにコピーします。
- テキストを変更します。各IDはページ内で一意に保ちます。
- キーボードでテストします。Tab、Enter、Space、矢印キー、Home、Endを使います。
- スクリーンリーダーでテストします。「展開」や「折りたたみ」、「タブ 2/3」のように読み上げられるはずです。
- 視差効果を減らす設定をオンにしてページを確認します。パネルはアニメーションなしで開くはずです。
- 見出し自体をクリック可能にするのではなく、見出しの中にボタンを置きましょう。見出しはフォーカスできず、状態も読み上げられません。
- 閉じたパネルにはhidden属性を使い、その中のリンクにTabキーで移動できないようにしましょう。
- タブの中にタブ、タブの中にアコーディオンを入れるのはやめましょう。利用者が今どこにいるのか分からなくなります。
- 回答が検索にとって重要なら、後から読み込むのではなく、非表示の状態でHTMLに残しておきましょう。そうすればクローラーと人が同じテキストを見られます。
よくある質問
タブは矢印キーで切り替えるべき?Enterで切り替えるべき?
ARIAの設計ガイドはどちらも認めています。パネルがすでに読み込まれている場合は、矢印の移動に合わせて切り替える方法(自動アクティベーション)が最も素早く感じられます。パネルの表示に時間がかかる場合は、矢印でフォーカスを移動し、EnterかSpaceで切り替えるようにしましょう。
JavaScriptで高さを測らずにアコーディオンの高さをアニメーションさせるには?
パネルをグリッドにして、grid-template-rowsを0frから1frへトランジションさせ、内側の要素にoverflow hiddenを指定します。高さはブラウザーが計算してくれます。
details要素はアクセシブルですか?
はい。ブラウザーはsummaryを展開状態を持つボタンとして公開し、最初からキーボードで操作できます。ただしマーカーのスタイル設定やアニメーションは難しく、多くのサイトが今でも独自に作っているのはそのためです。
非表示のアコーディオンの回答はSEOで評価されますか?
HTMLに含まれていて折りたたまれているだけのコンテンツは、引き続きクロールされます。クリック時に読み込むのではなくページのソースに含めておき、表示される回答がHTML内の内容と一致するようにしましょう。
次のステップ
- Reactを使っている場合は、コンポーネントギャラリーに、スライドする下線付きのタブセットとFAQのアコーディオンがあり、どちらもJSXをコピーできます。FAQセクションでは、質問と回答がページ上に表示されている場合に限り、対応するFAQPageの構造化データを追加しましょう。
よくある間違い
- クリックハンドラーを付けたdiv要素をアコーディオンの見出しに使うこと。Tabキーで移動できず、スクリーンリーダーにも操作できる要素だと伝わりません。
- すべてのタブをTabキーの移動順に含めること。キーボード利用者はコンテンツにたどり着くまで、すべてのタブを通過しなければならなくなります。
- 状態が変わったときにaria-expandedやaria-selectedの更新を忘れること。スクリーンリーダーが誤った状態を伝えてしまいます。
アコーディオン
高さのアニメーション付きのアクセシブルなアコーディオン
各見出しには、aria-expandedとaria-controlsを持つ本物のボタンが入っています。高さはグリッド行のトランジションでアニメーションするため、scrollHeightを測る必要がありません。Tab、Enter、Spaceで試してみてください。
一度に開くパネルは1つだけ
パネルを開いたら、開いている他のパネルを閉じます。これは任意にしておきましょう。2つの回答を比べたい人は、両方を開いておきたいことがよくあります。
JavaScriptなしのフォールバック:details要素とsummary要素
ネイティブのdetails要素は、スクリプトなしで開閉します。同じname属性を付けると、現在のブラウザーでは1つだけ開くようになります。古いブラウザーでは複数を開けるだけです。
タブ
ロービングtabindexと矢印キーで操作するタブ
選択中のタブだけがtabindex 0を持つため、Tabキーはタブリストに一度入った後、パネルへ移動します。左右の矢印キーでタブ間を移動し、HomeとEndで端へジャンプします。
キーボードとARIAのチェックリスト
キーボードテスト:デモでそれぞれ試してください
- Tab
- 次の見出しボタンへ移動
- 選択中のタブからタブリストに入り、その後パネルへ移動
- Shift + Tab
- 前の見出しボタンへ移動
- タブリストの外へ戻る
- EnterまたはSpace
- フォーカス中のパネルを開閉
- フォーカス中のタブを選択(手動アクティベーションの場合のみ必要)
- 右 / 左矢印キー
- 不要
- 次 / 前のタブ(端で先頭や末尾に戻る)
- Home / End
- 任意:最初 / 最後の見出し
- 最初 / 最後のタブ
ARIAリファレンス
各部分に必要な属性
- トリガー
- 見出し内のボタン、aria-expanded、aria-controls
- role=tab、aria-selected、aria-controls、tabindex 0または-1
- コンテナ
- 必須の属性なし
- aria-label付きのrole=tablist
- パネル
- id。aria-labelledby付きのrole=regionは任意
- role=tabpanel、aria-labelledby、フォーカス可能な内容がなければtabindex 0
- 非表示の状態
- 閉じたパネルにhidden属性
- 非アクティブなパネルにhidden属性
Reactを使っていますか? こちらから始めましょう:
Reactのタブコンポーネント
無料で始める · クレジットカード不要
関連: ガイド|Webマーケティングと集客を学ぶ
製品
ご利用いただける方
機能
リソース
会社情報
サイトマップを見る