多くのコンテンツをコンパクトに表示するために、よく用いられるタブ切り替えUIですが、スクリーンリーダーでの利用やキーボド操作を考慮した場合に、アクセシブルではないと思えるものが少なくありません。

例えば、スクリーンリーダー利用者はタブ切り替えUIであると認識することが難しいと思われます。タブ切り替えUIは一種のページ内リンクと考えられますので、一つのタブを選択したらそのタブが示す先のコンテンツにフォーカスが移動しなければなりません。しかし、多くのタブ切り替えUIは、タブを選択した後に[tab]キーを押すと、リンク先のコンテンツ内、あるいはその次のリンクにジャンプすることはなく、選択したタブの次のタブにフォーカスが移動します。つまり、ページ内リンクとして機能していないということになります。

そのため、これまで jQuery Accessible Tabs をよく利用していましたが、もっと気軽に、自由に設定できるように、jQuery Accessible Tabs の挙動を参考にして簡単な jQuery と CSS で実装してみました。

HTML は純粋にタブを目次としたページ内リンクとして記述しますが、リンク先の id は空の div 要素に指定しています。

オプションとして、タブの最後に「すべて表示」の選択肢を追加しています。また、スクリーンリーダー向けに先頭に注釈を、コンテンツの最後にタブ選択に戻るためのリンクを設置しています。

<div class="tabContent">
<p class="scrText">タブ形式で表示を切り替えています。</p>
<ul id="tabsList">
  <li><a href="#content1">コンテンツ1</a></li>
  <li><a href="#content2">コンテンツ2</a></li>
  <li><a href="#content3">コンテンツ3</a></li>
  <li><a href="#" class="all">すべて表示</a></li>
</ul>
<div id="content1" class="tabHead"></div>
<div class="tabBody">
(コンテンツ1の内容)
</div>
<div id="content2" class="tabHead"></div>
<div class="tabBody">
(コンテンツ2の内容)
</div>
<div id="content3" class="tabHead"></div>
<div class="tabBody">
(コンテンツ3の内容)
</div>
<p class="backToTab"><a href="#tabsList">タブ選択に戻る</a></p>
</div>

jQuery では、タブを選択すると一旦すべてのコンテンツを非表示にして、選択したタブと一致する id を持つ要素の次の要素を表示します。ただし、「すべて表示」のタブを選択した場合はすべてのコンテンツを表示します。

さらに、選択したタブに、スタイリングのための class="current" を設定し、スクリーンリーダー用に「表示中のタブ:」というテキストを追加しています。

<script>
jQuery(function($){
  $('#tabsList a').click(function(){
    if ($(this).attr('class') == 'all'){  // 「すべて表示」のタブを選択した場合
      $('.tabBody').fadeIn();  // すべてのコンテツを表示
    } else {
      $('.tabBody').hide();  // 一旦すべてのコンテツを非表示
      $(this.hash).next('.tabBody').fadeIn();  // 選択したタブと一致する id を持つ要素の次の .tabBody 要素を表示
    }
    $('#tabsList li').removeClass('current'); // 一旦すべてのタブの current クラスを削除
    $(this).parent('li').addClass('current'); // 選択したタブに current クラスを設定
    $('#tabsList li .scrText').remove();  // 一旦すべてのタブのスクリーンリーダ用テキストを削除
    $(this).prepend('<span class="scrText">表示中のタブ:</span>'); // 選択したタブにスクリーンリーダ用テキストを追加
  });
  $('#tabsList a:eq(0)').trigger('click'); // ページを開いた際に1番目のタブを選択した状態にする
});
</script>

ここまでの設定では、タブを選択した際に、ターゲットとなる id の要素に移動するため、画面のスクロールが発生します。それを防止する目的で、スクリプトの最後に本来のイベント処理をキャンセルするために return false; が記述されることが多いですが、それではリンクが機能しなくなるので、選択したコンテンツにフォーカスがジャンプしません。

また、公開されているタブ切り替えUIの中には、a 要素を使わないことで画面スクロールが発生しないものがありますが、そもそも a 要素がないとキーボードで操作することができません。マウスでクリックすることができる要素は、キーボードでもフォーカスできるようにすべきです。

そこで、CSS でターゲットの id を持つ要素を非表示とすることで、画面スクロールを起こさず、選択したコンテンツにフォーカスがジャンプするようにします。HTML でリンク先の id を空の div 要素に指定したのはこのためです。(タブやコンテンツ部分の CSS はそれぞれですので省略しています)

#tabsList li {
  float: left;
}
#tabsList li a {
  display: block;
  *****: *****;
}
#tabsList li a:hover,
#tabsList li a:focus {
  *****: *****;
}
#tabsList li.current a {
  *****: *****;
}
.tabHead  {
  display: none;
}
.tabBody {
  *****: *****;
}
.scrText,
.backToTab a {
  position: absolute;
  height: 0;
  overflow: hidden;
}
.backToTab a:focus {
  position: static;
  height: auto;
}

HTML 先頭のスクリーンリーダー用の注釈、選択したタブに追加した「表示中のタブ:」のテキスト、タブ選択に戻るリンクは画面上で非表示にします。

よく、スクリーンリーダー用のテキストが display: none; で画面から消されているのを見ますが、これはスクリーンリーダーにも認識されなくなりますので、スクリーンリーダー用のテキストの意味がありません。ここでは高さを 0 にして overflow: hidden; として画面から消しています。

その上で、画面を見てキーボードで操作するユーザーのため、タブ選択に戻るリンクにフォーカスされると、そのリンクが画面に表示されるようにしています。

タブ切り替えUIを使わないことが最もアクセシブルかもしれませんが、タブ切り替えUIがユーザービリティを向上させる場合もあります。

これでも十分にアクセシブルとは言えないかもしれませんが、タブ切り替えUIのように視覚的なUIでも、スクリーンリーダーやキーボード操作で戸惑わない配慮が必要と考えます。