タブUI - コピペで使えるアクセシビリティ対応モジュール
はじめに
こんにちは。株式会社VOWZ の Chikara です。
弊社では、定期的なアクセシビリティ講習の実施や、制作したWebページに対するアクセシビリティチェックなど、企業として継続的にアクセシビリティに取り組んでいます。
今回は、タブUI に関する解説をお届けします。
タブUIは、ul
要素のリストや input type="checkbox"
のような、HTML標準のセマンティクスが用意されていないため、div
要素などをカスタマイズして実装する必要があります。
モジュールだけを確認したい場合は、目次の【モジュール】をご参照ください。
基本編
【モジュール】タブUI - アニメーション無し
まずは実際の挙動を見ていただきます。
クリックすることによって目的のタブを選択することができます。
また、TABキーを押すことで「タブ1」がフォーカスされ、その後は矢印キーと決定キー(Enter または Space)で同様の操作が可能です。
HTMLの構成とアクセシビリティ対応
<!-- コンテンツ -->
<div class="tabs">
<h3 id="tablist-1">タブリスト見出し</h3>
<div role="tablist" aria-labelledby="tablist-1" class="manual">
<button id="tab-1" type="button" role="tab" aria-selected="true" aria-controls="tabpanel-1">
<span class="focus">タブ1</span>
</button>
<button id="tab-2" type="button" role="tab" aria-selected="false" aria-controls="tabpanel-2" tabindex="-1">
<span class="focus">タブ2</span>
</button>
<button id="tab-3" type="button" role="tab" aria-selected="false" aria-controls="tabpanel-3" tabindex="-1">
<span class="focus">タブ3</span>
</button>
<button id="tab-4" type="button" role="tab" aria-selected="false" aria-controls="tabpanel-4" tabindex="-1">
<span class="focus">タブ4</span>
</button>
</div>
<div id="tabpanel-1" role="tabpanel" aria-labelledby="tab-1">
<p>これはタブ1のサンプルテキストです。</p>
</div>
<div id="tabpanel-2" role="tabpanel" aria-labelledby="tab-2" class="is-hidden">
<p>これはタブ2のサンプルテキストです。</p>
</div>
<div id="tabpanel-3" role="tabpanel" aria-labelledby="tab-3" class="is-hidden">
<p>これはタブ3のサンプルテキストです。</p>
</div>
<div id="tabpanel-4" role="tabpanel" aria-labelledby="tab-4" class="is-hidden">
<p>これはタブ4のサンプルテキストです。</p>
</div>
</div>
<div class="tabs">
この要素は、タブUI全体を包む親要素です。複数のタブボタンと、それに対応するタブパネル(コンテンツ)を内包します。
<h3 id="tablist-1">タブリスト見出し</h3>
タブグループのセクションを示す見出し要素です。id
属性を用いることで、後述するタブリストとの関連付けが可能になります。
<div role="tablist" aria-labelledby="tablist-1" class="manual">
この部分がタブのボタンが並ぶリストになります。
-
role="tablist"
:この要素が「タブリスト」であることを、スクリーンリーダーに伝えます。 -
aria-labelledby="tablist-1"
:見出し(h3
)と関連付けることで、「このタブリストはどんな内容のものか」を補足的に説明できます。
<button id="tab-1" type="button" role="tab" aria-selected="true" aria-controls="tabpanel-1">
個々のタブボタンを表す要素です。
-
role="tab"
:このボタンが「タブ」であることを明示します。 -
aria-selected="true"
:現在選択されているタブにはtrue
、それ以外はfalse
を設定します。 -
aria-controls="tabpanel-1"
:このタブが制御しているパネルのIDを指定します。
<div id="tabpanel-1" role="tabpanel" aria-labelledby="tab-1">
タブボタンに対応するコンテンツ領域(タブパネル)です。
-
role="tabpanel"
:このエリアがタブの内容部分であることを示します。 -
aria-labelledby="tab-1"
:どのタブボタンに対応しているかをスクリーンリーダーが理解できるようにします。
<div class="is-hidden">
非表示状態のタブパネルに付与されるクラスです。CSSとJavaScriptを使って表示・非表示を切り替えます。
role属性について
今回のタブUIでは、主に tablist
、tab
、tabpanel
の3つの role
属性が使われています。
以下は構造を簡略化したコード例です。
<div role="tablist">
<button role="tab" aria-selected="true" aria-controls="tabpanel-1" id="tab-1">タブ1</button>
<button role="tab" aria-selected="false" aria-controls="tabpanel-2" id="tab-2">タブ2</button>
<button role="tab" aria-selected="false" aria-controls="tabpanel-3" id="tab-3">タブ3</button>
</div>
<div role="tabpanel" id="tabpanel-1" aria-labelledby="tab-1">
<p>タブ1の内容</p>
</div>
<div role="tabpanel" id="tabpanel-2" aria-labelledby="tab-2" hidden>
<p>タブ2の内容</p>
</div>
<div role="tabpanel" id="tabpanel-3" aria-labelledby="tab-3" hidden>
<p>タブ3の内容</p>
</div>
この例からもわかるように、tablist
の中に tab
が並び、それぞれのタブに対応する tabpanel
は外側に配置されています。
アクセシビリティの観点では、以下のルールを押さえておくことが重要です。
-
role="tab"
は 必ずrole="tablist"
の直接の子要素である必要があります。 -
role="tabpanel"
はtablist
の中に含まれている必要はなく、aria-labelledby
属性で対応するタブと関連付けることで正しく機能します。
💡よくある間違いや注意点
次のように、
tab
をdiv
で囲んでしまうと、tablist
の直接の子要素でなくなり、スクリーンリーダーが正しく認識できない可能性があります。<div role="tablist"> <div> <button role="tab" aria-controls="tabpanel-1" id="tab-1">タブ1</button> </div> <div> <button role="tab" aria-controls="tabpanel-2" id="tab-2">タブ2</button> </div> </div>
応用編
【モジュール】タブUI - アニメーション①
【モジュール】タブUI - アニメーション②
基本編パーツとの違い
基本編で行われている処理
基本編で使用されているJavascriptでは以下の処理を行なっています。
this.tabpanels[i].classList.remove('is-hidden');
...
this.tabpanels[i].classList.add('is-hidden');
- 表示すべきタブパネルから
is-hidden
クラスを削除して表示。 - 非表示にするパネルには
is-hidden
クラスを付与して非表示にします。-
is-hidden
クラスは、CSSでdisplay: none;
などの非表示スタイルを設定しています。
-
応用編で行われている処理
this.tabpanels[i].classList.add('is-active');
...
this.tabpanels[i].classList.remove('is-active');
- 表示すべきタブパネルに
is-active
クラスを追加。 - それ以外のパネルからは
is-active
クラスを除去します。-
is-active
クラスは、CSSでdisplay: block;
やopacity: 1;
などの表示用スタイルを与えます。
-
比較
項目 | 基本編 | 応用編 |
---|---|---|
タブのデフォルトスタイル | 表示 | 非表示 |
クラス付与後のスタイル | 非表示(is-hidden ) |
表示(is-active ) |
クラスが付与される対象 | 表示されていないタブ | 表示されているタブ |
CSSの想定 | display: none; |
display: block; , visibility , opacity
|
まとめ
タブUIは、Webサイトでも使用頻度の高いUIのひとつですが、実際に使われているものの中には、「キーボード操作ができない」「role属性などのマークアップがまったく行われていない」といった課題を抱えているケースも少なくありません。
今回ご紹介したモジュールについては、すべての支援技術での完全な動作保証まではできないものの、Chromeの拡張機能「axe DevTools」でのアクセシビリティチェックをクリアしたものを掲載しています。
アクセシブルなサイトづくりを目指すエンジニアの皆さまにとって、ささやかでも一助となれば幸いです。
※本記事で掲載されているモジュールは、W3Cによる ARIA Authoring Practices を引用・調整したものです。ライセンスは W3C Software License に準拠します。
Discussion