Accessibility

アクセシビリティ

v3用のドキュメントを参照しています

はじめに

Splideは、W3C Carousel Conceptsが示す基準になるべく添うよう配慮しながら、スライダーのアクセシビリティ向上を図っています。このガイダンスは、次のような4つの基本要件を提示しています。

  • キーボードあるいは音声入力を使っているユーザが、個々のスライドを移動できること
  • スクリーンリーダを用いているユーザが、現在どのスライドが表示されており、かつどのようにすれば別のスライドに移動するかを理解できること
  • ものの動きに気がとられてしまう人のために、アニメーションを停止できる手段を提供すること
  • スライド内のコンテンツを読むのに時間がかかってしまう人のために、アニメーションを停止できる手段を提供すること。同時に、スライド内のコンテンツを読むための十分な時間を確保すること

自動再生の機能により、後半2つの問題はすでに解決されています。W3Cは再生・停止ボタンの提供を勧めていますが、配置するかどうかはご自身で決めてください。

以下、前半の2点について、Splideではどのような対応がなされているかについて説明していきます。

キーボード操作

ショートカット

ユーザは、矢印キーを用いてスライダーを操作できます。

ショートカット説明
LTRでは前の、RTLでは次のページに移動
LTRでは次の、RTLでは前のページに移動
TTBで前のページに移動
TTBで次のページに移動

デフォルトでは、Splideはdocumentkeydownを監視しているため、仮に1ページ内に複数のスライダーが配置されている場合、すべてが同時に反応します。もしこの動作が好ましくない場合、keyboardオプションを'focused'に設定すると、アクティブ要素(フォーカスを持った要素)を内包したスライダーのみが反応するようになります。なお、このときスライダーのルート要素には自動的にtabindex="0"が追加されます。これはスライダーが、フォーカスできる要素を一つも持っていない可能性への対策です。

Intersectionエクステンションを利用すると、スライダーがビューポート内にある場合にのみキー入力を受け付けるように設定できます。

タブキーによる操作

ユーザはTabキーを用いて、現在見えているスライド、矢印ボタンおよびページネーションを移動できます。

  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09

slideFocusオプションをfalseにすればスライドへのフォーカスを無効にできますが、この場合は最初に引用した要件の1つ目を満足できなくなりますので注意してください。

フォーカスされた要素を強調表示するには、:focus疑似セレクタを利用してスタイルを追加する必要があります。

ページネーション

このW3Cのチュートリアルでは、キーボード、あるいはそのほかの支援技術を使用しているユーザのために、ページネーションのボタンが押された際、対応するスライドにフォーカスを戻すことを勧めています。

ユーザがこれらのナビゲーションボタンを選択した際、選択された項目に対してフォーカスを設定すべきです。このケースでは、スライダーが変化、あるいは移動した後、currentクラスを持つ<li>要素に対してフォーカスを移動する必要があります。これにより、キーボードあるいは支援技術を使用するユーザは、より簡単にスライダーを操作できるようになります。

Splide v2にはこのような機能はありませんでしたが、v3で実装されました。下のスライダーのページネーションをクリックして、フォーカスの移動を確かめてみてください。

  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09

フォーカス可能な要素

Splideは、スライダーの表示領域に完全に収まっていないスライドに対してaria-hidden属性を割り当て、スクリーンリーダ、あるいはその他の支援技術がそれらのスライドを認識しないようにしています。ところが、スライド自体に<input><textarea>などのフォーカス可能な要素が含まれている場合、Tabにより依然として、隠れた要素にフォーカスを移動できてしまいます。

Lighthouseがこのような不親切な要素を検出すると、以下のような警告を発し、是正を促します。

[aria-hidden="true"]が設定された要素の中にフォーカス可能な子孫要素を配置してしまうと、スクリーンリーダなどの支援技術を使用するユーザがこれらの要素を使用できなくなります。

この問題に対応するため、Splideは隠れているスライドが含む以下の要素に対してtabindex="-1"を適用し、一時的にフォーカスできないようにしています。

  • <a>
  • <button>
  • <textarea>
  • <input>
  • <select>
  • <iframe>

ほとんどの場合この対応でうまくいきますが、上記に漏れる以下の要素が含まれている場合は追加対応が必要です。

  • <area>
  • <audio controls>
  • <summary>
  • <video controls>
  • contenteditable属性が有効になっている要素
  • tabindex="0"を持った要素

どの要素に対してtabindex="-1"を適用するかは、focusableNodesオプションの値が決定しています。この値はセレクタですので、次のようにして検索対象を増やしたり、逆に不必要な要素を減らしたりできます。

{
focusableNodes: 'a, button, ..., area, [contenteditable]',
}
JavaScript

ただし、残念ながらtabindex="0"が設定された要素が含まれる場合、このオプションだけではうまく対応できません。これは、-1に設定した後に再びスライドが表示された際、0(あるいはその他の整数値)に戻す処理が必要になるためです。スライダーの中でtabindexを用いてフォーカスを制御することはないと信じたいですが、仮にそのような対処が必要になった場合は、visibleおよびhiddenイベントを利用すればインデックスの切り替えを実装できます。

ARIA属性

矢印のボタンやページネーションなど、インタラクション可能なすべての要素には、適切なARIA属性が割り当てられます。ただし、ラベル等に割り当てられているテキストは英語ですので、ユーザ層に合わせて適宜翻訳してください。

各スライド

aria-hidden

ビューポートに収まりきっていないスライドに対してtrueが設定される

矢印

aria-controls

トラック要素のIDが設定される

aria-label

「前」の矢印には"Previous slide(前のスライドへ)"または"Go to last slide(最後のスライドへ)"が、「次」の矢印には"Next slide(次のスライド)"または"Go to first slide(最初のスライドへ)"が割り当てられる

また、矢印はそれ以上進めなくなった際、disabled属性が付与されます。

ページネーション

aria-controls

スライドのID。複数枚表示される場合、すべてのIDが対象となる

aria-label

"Go to slide %s(スライド%sへ)"または"Go to page %s(ページ%sへ)"が割り当てられる

再生・停止ボタン

aria-controls

トラック要素のIDが設定される

aria-label

再生ボタンには"Start autoplay(自動再生を始める)"が、停止ボタンには"Pause autoplay(自動再生を中断)"が割り当てられる

ナビゲーション

isNavigationオプションを有効にした場合、スライダー自身がほかのスライダーを制御するナビゲーションとしてふるまいます。このようなスライダーに対しては、リスト要素にmenuロールが、各スライドにはmenuitemロールが割り当てられます。

リスト要素

role

'menu'

各スライド

role

'menuitem'

aria-controls

コントロール対象となるスライダーのID。対象が複数の場合は、すべてのIDが含まれる

aria-label

"Go to slide %s(スライド%sへ)"が割り当てられる

アクティブスライドの通知

W3Cの提案の中で唯一、WAI-ARIA regionを利用した「アクティブスライドの通知」には対応していません。

WAI-ARIAのライブリージョンを用いて、現在表示されている項目が何なのかをスクリーンリーダに知らせて下さい。

しかしながら、「スライダーが移動するたびに現在のスライドをリーダに読ませるとうるさい」という別の意見もあります(特に自動再生が有効な場合は顕著です)。Splide v3ではこの機能の導入を見送ることにしましたが、もし必要な場合は、以下のような拡張機能を作成することで実装できます。

export function LiveRegion( Splide ) {
let liveRegion;
function mount() {
liveRegion = document.createElement( 'div' );
liveRegion.setAttribute( 'aria-live', 'polite' );
liveRegion.setAttribute( 'aria-atomic', 'true' );
liveRegion.classList.add( 'visually-hidden' );
Splide.root.appendChild( liveRegion );
Splide.on( 'moved', onMoved );
}
function onMoved() {
liveRegion.textContent = `Slide ${ Splide.index + 1 } of ${ Splide.length }`;
}
function destroy() {
Splide.root.removeChild( liveRegion );
}
return {
mount,
destroy,
}
}
JavaScript

この拡張機能は主に、次のようなことをしています。

  • ライブリージョンフィールドの作成
  • スライドが移動したのち、フィールドのテキストを更新

しかしこのままではテキストが表示されてしまいますので、いわゆる「視覚的に隠す」方法を用いて、スクリーンリーダには検出可能、かつ人間には見えないようにする必要があります。

.visually-hidden {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
CSS

Splideを初期化する際、この拡張機能を登録すれば実装完了です。

import { LiveRegion } from '...';
new Splide( '.splide' ).mount( { LiveRegion } );
JavaScript

下のスライダーを用いれば、結果を確認できます。スクリーンリーダを起動し、スライダーを移動してみてください。移動が完了するたびに、リーダが現在のスライド番号を読み上げます。

  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09