その他

カルーセル

解説あり

Carousel

自動で切り替わるスライド。再生/停止と読み上げ配慮が重要。

カルーセル(Carousel)とは?

カルーセルは、複数のスライド(バナー・特集・写真など)を同じ場所で順番に切り替えて見せる UI です。 トップページのヒーローバナーや商品ギャラリーでよく使われます。

便利な反面、勝手に動く止められないキーボードで操作できないと なりがちで、アクセシビリティの問題が起きやすいパターンの代表格です。

なぜアクセシビリティが大事なの?

ライブデモ(推奨実装)

下のカルーセルは APG に沿った実装です。再生/停止・前/次をキーボードで操作してみてください。

アクセシブルなカルーセル
初夏のセール全品10%オフ

試してみよう:4秒ごとに自動で進みます。⏸ で停止 → ‹ › で前後に移動 → カルーセルにマウスを乗せる/フォーカスを当てると自動回転が一時停止します。

ポイント

aria-roledescription を付けると、スクリーンリーダーが領域を 「おすすめ特集, カルーセル」、各スライドを「3枚中1枚目, スライド」のように 案内します(任意ですが分かりやすくなります)。再生/停止ボタンのラベルは 状態に合わせて「自動再生を停止/開始」と切り替えます。

キーボード操作

操作動作必須/任意
TabEnter/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> でフォーカスできず、 スライドに位置ラベルもありません。

止められない自動回転カルーセル
特集1

試してみよう: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" も「○枚中○枚目」ラベルもない。

実装チェックリスト


原文(英語):Carousel Pattern — W3C APG(新しいタブで開きます)