画像スライドショーをアクセシブルにカスタマイズする (PhotoSwipe を例に)
以前、「画像スライドショーの標準 UI (あったらいいな)」という記事を書きましたが、現実問題として、ウェブサイトで画像のスライドショーを実現するには、JavaScript ライブラリーを付加的に使うことになります。最近「PhotoSwipe」というスライドショーの全画面表示が可能なライブラリーを使う機会があり、アクセシビリティ面でのカスタマイズを加えることで、自分の思い描くインタラクションに近づけることができました。ひとつの実験例としてご紹介します。(この記事の最後にデモへのリンクをご用意していますので、併せてご覧ください。)
PhotoSwipe の特長
PhotoSwipe には、以下の特長があります。ユーザーエクスペリエンス (特にユーザーの没入感) や、ユーザビリティ上の配慮といった点で、うまくできているなという印象です。
- 全画面表示が手軽にでき、ユーザーの意識がスライドショーの画像に集中しやすくなる。(下記註1参照)
- スライドショー画面 (全画面表示状態を含む) で、画像をさらにズームできる。(下記註2参照)
- ブラウザの「戻る」ボタンを押すと、スライドショーを閉じて元ページに戻る。一般的なモーダルウィンドウ (Lightbox 系) にありがちな、さらに前の履歴 (元ページの前に開いていたページ) にまで戻ってしまう問題がない。
- スライドショー画面で、画像の外側の領域をクリックまたはタップしたときの挙動が自然。PC の場合、画像の外側をクリックするとスライドショーを閉じる (「×」ボタンの拡張として機能する)。スマートフォンやタブレットの場合、スライドショーを閉じない (うっかり画像の外側に触れてしまった際のフェイルセーフとして機能する)。
- タッチジェスチャへの対応。スライドショー画面でピンチアウトすると画像をズームすることができる。ダブルタップでズームイン/アウトができる。左右スワイプでスライドショーの画像を切り替えることができる。ピンチインまたは上下スワイプで、スライドショーを閉じることができる。
PhotoSwipe のアクセシビリティ
一方、PhotoSwipe のアクセシビリティはどうでしょうか。この手のインタラクションで見落とされがちなアクセシビリティ要件としては :
- キーボード操作が可能なこと
- スクリーンリーダーで必要な情報が読み上げられること
...のふたつが大きいと思いますが、実際に PhotoSwipe を例に、アクセシビリティの改善を試みたいと思います。
キーボード操作が可能なこと
PhotoSwipe では、基本的なキーボード操作は担保されています。[Tab] キーによるフォーカス移動と [Enter] キーによる実行によって、スライドショーを開いたり、各機能 (アイコン) を利用することができます。また、左右矢印キーで画像を切り替えたり、[Esc] キーでスライドショーを閉じることもできます。
ただしデフォルト (ライブラリーをカスタマイズせず実装した状態) では、スライドショー画面上で [Tab] キーを用いてフォーカス移動させていると、いつのまにかフォーカスがどこかへ消えてしまう (スライドショーは開いたまま、実は背景側の元ページにフォーカスが移ってしまう) 現象が見られます。特に視覚障害者にとっては、スライドショーを開いていたつもりなのになぜかスライドショー画面に無いはずの情報がスクリーンリーダーで読み上げられてしまうことで、状況がのみ込めず混乱しそうです。
この問題を解決するには、スライドショー起動中は背景側のコンテンツ要素に aria-hidden="true" を適用するようにします。たとえば、背景側のコンテンツ全体を包含する要素を id="base" として、ライブラリーの JavaScript ファイルのしかるべきところ (スライドショーを開く設定が記述されているところ) に、下記を追記します。
document.getElementById('base').setAttribute('aria-hidden','true');
逆に、スライドショーを閉じたときは背景側のコンテンツ要素に aria-hidden="false" を上書き適用するように、JavaScript ファイルのしかるべきところ (スライドショーを閉じる設定が記述されているところ) に下記を追記します。
document.getElementById('base').setAttribute('aria-hidden','false');
なお、aria-hidden 属性はあくまでも支援技術 (スクリーンリーダー) に対するコマンドです。目の見えるユーザーがスクリーンリーダーを併用せずキーボード操作する場合でも、フォーカスがスライドショー画面上に留まるようにしたいものです。背景側のコンテンツ要素に aria-hidden="true" が適用されているときは、CSS で display:none; を適用します。
#base[aria-hidden="true"] { display: none; }
もうひとつ、忘れてはならないのは、スライドショーを閉じたときのフォーカス制御です。デフォルト (ライブラリーをカスタマイズせず実装した状態) では、スライドショーを閉じるとフォーカスが消える ([Tab] キーを押すと、元ページの先頭からフォーカス移動が「やり直し」になる) 挙動になっています。この問題を解決するには、スライドショー終了時にフォーカスを当てたい要素に id 属性 (たとえば id="focus_when_gallery_closed" とします) を追記し、ライブラリーの JavaScript ファイルのしかるべきところ (スライドショーを閉じる設定が記述されているところ) に、下記を追記するとよいでしょう。
document.getElementById('focus_when_gallery_closed').focus();
スクリーンリーダーで必要な情報が読み上げられること
PhotoSwipe では、各機能 (アイコン) にフォーカスを当てると、スクリーンリーダーによってそのアイコン名 (<button> 要素の title 属性) が読み上げられます。ただアイコン名のラベルはデフォルト (ライブラリーをカスタマイズせず実装した状態) では英語なので、日本語話者ユーザーを対象とした場合、ラベルを日本語化したいことでしょう。そのカスタマイズは、PhotoSwipe を実装する際の所定の HTML コード内で可能です。
もうひとつ、この手のインタラクションでは、スライドショー起動時およびスライドショーの画像切替時に、その画像のキャプションやカウンター (何枚中、何枚目か) が同時に読み上げられるようにしたいものです。スライドショー全体を包含する <div> 要素に aria-describedby 属性を記述して、カウンターおよびキャプションの要素と紐付けておくと、スライドショー起動と同時にカウンターとキャプションが読み上げられます。さらに、カウンターおよびキャプションの要素にそれぞれ aria-live 属性を記述すると、スライドショーの画像切替のたびに、カウンターとキャプションが読み上げられます (属性値は assertive でなくても、polite でも十分そうです)。これらのカスタマイズも、PhotoSwipe を実装する際の所定の HTML コード内で可能です。
実は上記に加えて、スライドショー起動時に aria-describedby を使ってイントロダクションを読み上げさせることも検討しましたが (「スライドショー画面を開きました。左右矢印キーで画像を切り替えることができます。Escape キーでスライドショーを閉じることができます。」という具合に)、実際に試したところやや情報過多な感じがしたので、今回は不採用としました。特定のユーザーエージェントで見られるアクセシビリティ上の不具合
以上で基本的なアクセシビリティ要件をカバーできていて欲しいところですが、実際には、特定のユーザーエージェント (ブラウザとスクリーンリーダーの組み合わせ) で若干の不具合があります。PhotoSwipe 特有の話ではありますが、下記にメモします。
Windows の場合
Firefox + NVDA の組み合わせでは問題ありませんが、他のブラウザで下記の現象が見られます。
- IE + NVDA : スライドショー起動時、カウンターは正しく読み上げられるものの、画像キャプションはすべて (開いていない画像の分も含めて) 読み上げられてしまう。(ただしスライドショー起動後の画像切替においては、カウンター、キャプションとも問題なく適切に読み上げられる。)
- Chrome + NVDA : スライドショーを起動しても NVDA がフォーカスモードに切り替わらない (ユーザーが手動で NVDA のモードを切り替える必要がある)。また、スライドショーの画像を切り替えると、カウンターとキャプションが何度も繰り返し読み上げられてしまう。
Mac OS X の場合
Safari または Chrome で VoiceOver を併用時に、スライドショーの画像を切り替えると、キャプションは読み上げられるものの、カウンターは読み上げられないという現象が見られます。(ちなみに Firefox + VoiceOver の組み合わせでは、現時点では残念ながらキャプションも読み上げられません。)
また、デフォルト (ライブラリーをカスタマイズせず実装した状態) では、スライドショー起動時に画像ファイル名が読み上げられてしまう現象が見られますが、これについては、PhotoSwipe を実装する際の所定の HTML コードで、以下のように aria-hidden="true" を追記することで解消できました。
<div class="pswp__container"> <div class="pswp__item" aria-hidden="true"></div> <div class="pswp__item" aria-hidden="true"></div> <div class="pswp__item" aria-hidden="true"></div> </div>なお、この aria-hidden 属性の追記は、iOS において見られる問題 (スワイプ操作で VoiceOver のフォーカスを移動させると、スライドショー画面全体にフォーカスが当たって画像ファイル名が読み上げられてしまう現象) の解消にもなりました。
iOS の場合
PhotoSwipe のデフォルト (ライブラリーをカスタマイズせず実装した状態) では、タッチスクリーンデバイスでの利用時、画像切替の左右矢印アイコンが非表示になります。恐らく左右スワイプ操作を前提にしているからですが、VoiceOver を併用している場合、左右矢印アイコンが表示されていないと (そこにフォーカスを当てることができないと) スライドショーの画像を切り替えることができません (Andoroid Chrome では TalkBack 併用時でも2本指スワイプで画像切替が可能ですが、iOS の場合 Safari をはじめ各ブラウザで、VoiceOver 併用時に3本指スワイプによる画像切替ができないのです)。これについては、PhotoSwipe ライブラリーの default-skin.css で「/* no arrows on touch screens */」というコメント以下に設定記述があるので、それらを消す (コメントアウトする) ことで、デバイスの種類を問わず左右矢印アイコンを表示させることができました。
Android の場合
Chrome + TalkBack の組み合わせでは、スライドショーの起動時および画像切替時に、キャプションは問題なく読み上げられるものの、カウンターが正しく読み上げられない (開いていない画像の分も含めて、すべてのカウンターが読み上げられてしまうことがある) 現象が見られます。なお Firefox + TalkBack の組み合わせでは、カウンター、キャプションともに問題なく読み上げられます。
デモ
以上のカスタマイズを反映した PhotoSwipe のデモをご用意しました。ご参考になれば幸いです。
(2016年2月25日追記)
PhotoSwipe の開発者から、たいへんありがたいことに Twitter で mention をいただきました。
@caztcha thanks a lot for the article, read it via rough Google Translate ^^, will try to improve myself
— PhotoSwipe (@PhotoSwipe) 2016年2月21日
よい機会なので、PhotoSwipe の GitHub にサマリーを投稿しました (Accessibility improvements of PhotoSwipe · Issue #1077)。「will try to include some of these in a core.」とのことですので、楽しみにしたいと思います。