その他
カルーセル
解説ありCarousel
自動で切り替わるスライド。再生/停止と読み上げ配慮が重要。
カルーセル(Carousel)とは?
カルーセルは、複数のスライド(バナー・特集・写真など)を同じ場所で順番に切り替えて見せる UI です。 トップページのヒーローバナーや商品ギャラリーでよく使われます。
便利な反面、勝手に動く・止められない・キーボードで操作できないと なりがちで、アクセシビリティの問題が起きやすいパターンの代表格です。
なぜアクセシビリティが大事なの?
- 自動で動くコンテンツが苦手な人。動き続けるバナーは、読むのが遅い人・注意の維持が難しい人・ 前庭障害などで動きに敏感な人にとって大きな負担です。停止できることが必須です (WCAG 2.2.2「一時停止、停止、非表示」)。
- キーボードだけで操作する人。前/次/再生停止が
<div>だと操作できません。 ネイティブの<button>で実装します。 - スクリーンリーダーを使う人。各スライドに「3枚中1枚目」のようなラベルがないと、 全体で何枚あり今どこかが分かりません。自動回転中に内容が読み上げられ続けると混乱するため、 回転中は
aria-liveを切るのがコツです。
ライブデモ(推奨実装)
下のカルーセルは APG に沿った実装です。再生/停止・前/次をキーボードで操作してみてください。
試してみよう:4秒ごとに自動で進みます。⏸ で停止 → ‹ › で前後に移動 → カルーセルにマウスを乗せる/フォーカスを当てると自動回転が一時停止します。
ポイント
aria-roledescription を付けると、スクリーンリーダーが領域を 「おすすめ特集, カルーセル」、各スライドを「3枚中1枚目, スライド」のように 案内します(任意ですが分かりやすくなります)。再生/停止ボタンのラベルは 状態に合わせて「自動再生を停止/開始」と切り替えます。
キーボード操作
| 操作 | 動作 | 必須/任意 |
|---|---|---|
| Tab → Enter/Space(再生停止ボタン) | 自動回転の再生 / 停止を切り替える | 必須(自動回転する場合) |
| Enter/Space(前/次ボタン) | 前 / 次のスライドへ手動移動(移動すると自動回転は停止) | 必須 |
| フォーカス / ホバー | カルーセル内にフォーカス・マウスがある間は自動回転を一時停止 | 必須 |
補足
「再生/停止ボタン」は、スライドより前(DOM 上で先)に置くのが推奨です。 キーボード利用者が動きに気づいたとき、すぐ止められるようにするためです。
必要な WAI-ARIA / ロール
| 付ける場所 | 属性 / ロール | 意味 |
|---|---|---|
| カルーセル全体 | aria-roledescription="carousel" + aria-label | カルーセルであることと名前を伝える(任意・推奨)。 |
| 再生/停止ボタン | <button> + 状態に応じた aria-label | 自動回転を止め/再開できるようにする(自動回転時は必須)。 |
| 前/次ボタン | <button> + aria-label | アイコンだけでも目的が伝わるようラベルを付ける。 |
| 各スライド | role="group" + aria-roledescription="スライド" + aria-label="3枚中1枚目" | 全体の枚数と現在位置を伝える。 |
| スライドの箱 | aria-live="off | polite" | 自動回転中は off、停止/手動中は polite に切り替える。 |
| 非表示スライド | hidden | 表示中以外は読み上げ/操作の対象外にする。 |
実装:推奨パターン(Good)
良い例 / 推奨
自動回転には再生/停止ボタンを必須で用意し、フォーカス/ホバーで一時停止。 前/次もネイティブの <button>。各スライドに位置ラベルを付けます。
マークアップ:
<section class="carousel"
aria-roledescription="carousel"
aria-label="おすすめ特集">
<!-- 自動回転するなら 再生/停止ボタンは必須 -->
<div class="carousel-controls">
<button type="button" aria-label="自動再生を停止" data-toggle>⏸</button>
<button type="button" aria-label="前のスライド" data-prev>‹</button>
<button type="button" aria-label="次のスライド" data-next>›</button>
</div>
<div class="carousel-slides">
<div role="group" aria-roledescription="スライド" aria-label="3枚中1枚目">
…スライド1…
</div>
<div role="group" aria-roledescription="スライド" aria-label="3枚中2枚目" hidden>
…スライド2…
</div>
<div role="group" aria-roledescription="スライド" aria-label="3枚中3枚目" hidden>
…スライド3…
</div>
</div>
</section>再生制御と一時停止のスクリプト:
let index = 0;
let playing = true;
let timer = null;
function show(i) {
index = (i + slides.length) % slides.length;
slides.forEach((s, n) => (s.hidden = n !== index));
}
function start() {
playing = true;
toggle.setAttribute('aria-label', '自動再生を停止');
// 自動回転中は読み上げが暴れないよう live を off に
slidesBox.setAttribute('aria-live', 'off');
timer = setInterval(() => show(index + 1), 4000);
}
function stop() {
playing = false;
toggle.setAttribute('aria-label', '自動再生を開始');
// 停止/手動操作中は変化を読み上げる
slidesBox.setAttribute('aria-live', 'polite');
clearInterval(timer);
}
toggle.addEventListener('click', () => (playing ? stop() : start()));
prev.addEventListener('click', () => { stop(); show(index - 1); });
next.addEventListener('click', () => { stop(); show(index + 1); });
// フォーカス/ホバー中は自動回転を一時停止
carousel.addEventListener('mouseenter', () => playing && clearInterval(timer));
carousel.addEventListener('mouseleave', () => playing && start());
carousel.addEventListener('focusin', () => playing && clearInterval(timer));
carousel.addEventListener('focusout', () => playing && start());アンチパターン(Bad)
下は止められない自動回転のカルーセルです。矢印は <div> でフォーカスできず、 スライドに位置ラベルもありません。
試してみよう:2秒ごとに勝手に進み、止める手段がありません。Tab で矢印にフォーカスできず、スクリーンリーダーでは何枚目かも分かりません。
<!-- ❌ アンチパターン -->
<div class="carousel">
<!-- 停止できない自動回転・スライドのラベルなし -->
<div class="slides">
<div class="slide">特集1</div>
<div class="slide" style="display:none">特集2</div>
</div>
<!-- div の矢印はフォーカスできない -->
<div class="arrow" onclick="prev()">‹</div>
<div class="arrow" onclick="next()">›</div>
</div>
<script>
// 止める手段がない無限自動回転
setInterval(next, 2000);
</script>悪い例 / 避ける
この実装の問題点:
- 停止できない — 再生/停止ボタンがなく、WCAG 2.2.2 違反。動きに弱い人が読めない。
- フォーカス/ホバーでも止まらない — 操作中も勝手に切り替わる。
- 矢印がフォーカス不可 —
div+onclickでキーボードから操作できない。 - 位置が伝わらない — スライドに
role="group"も「○枚中○枚目」ラベルもない。
実装チェックリスト
- 自動回転するなら再生/停止ボタンを必須で用意している
- フォーカス/ホバーの間は自動回転が一時停止する
- 前/次/再生停止はすべてネイティブの
<button>(divを使わない) - アイコンボタンに
aria-label、停止/開始でラベルを切り替えている - 各スライドに
role="group"+ 「○枚中○枚目」のラベルがある - 自動回転中は
aria-live="off"、停止/手動時はpolite - 表示中以外のスライドは
hidden aria-roledescription="carousel"(任意)、フォーカスが見える