本文へスキップ

カルーセル

横並びスライドを矢印・ドット・スワイプで切り替える。scroll-snap で滑らかに止まり、Pointer Events でタッチスワイプにも対応。

プレビュー

ドラッグ

操作ドラッグ/スワイプで操作できます(PC・スマホ対応)。

使いどころ

商品写真・キービジュアル・お知らせのように、複数の候補を同じ枠内で切り替えて見せたいときに使う。ドット・矢印・スワイプの3経路を揃えられるので、PCとスマホの両方で自然な操作感になる場面に向く。ただし2枚目以降がほとんど見られないことは計測でも知られており(いわゆる『カルーセル無視』)、重要な訴求やCTAを2枚目以降だけに置くのは避け、最初のスライドで完結させるか、そもそもグリッド表示に切り替えるべき。要素数が2〜3枚程度で全部いっぺんに見せられるなら、横スクロールのカードリストの方が一覧性が高くこの演出は不要。自動再生を足す場合は最低でも4秒は見せ、ホバー/フォーカスで止める設計が要る(今回のデモには自動再生は無い)。

仕組み

土台は overflow-x: auto と scroll-snap-type: x mandatory を掛けた .cr-track で、各スライドは flex: 0 0 100% と scroll-snap-align: start を持つ。矢印・ドットのクリックは track.scrollTo({left: slideW*current, behavior:'smooth'}) でネイティブスクロールを動かすだけで、位置管理は snap に任せている。現在位置は track の scroll イベントで scrollLeft を clientWidth で割った丸め値を current に同期させることで、ネイティブのタッチスワイプで動いた場合もドット・矢印の状態が正しく追従する。ルート要素の pointerdown/pointerup で開始点との差分(dx)を見て前後に送るのはマウス・ペン操作向けの補助で、タッチではブラウザ自身のスクロール操作に任せてポインタをキャプチャしない(キャプチャすると指の動きに対するネイティブの慣性スクロールが使えなくなる)。

実装の注意

ボタンやドットの上で pointerdown を拾ってしまうとクリックが発火しなくなる。この実装は e.target.closest('.cr-btn') と '.cr-dot' で早期リターンし、スワイプ判定に巻き込まないようにしている。これを忘れると『矢印を押しても反応しない』不具合になる。scroll-snap-type: x mandatory は要素の幅が半端だとスナップ位置がずれることがあるため、flex: 0 0 100% のように『必ずコンテナ幅ちょうど』になる指定を崩さないこと。overflow-x: auto に scrollbar-width: none と ::-webkit-scrollbar { display: none } を両方入れないと、OSやブラウザによってスクロールバーが常時表示されて見た目が崩れる。scroll イベントの同期処理を passive にしないと、スクロール中にフレーム落ちが起きやすい。

アクセシビリティ

矢印ボタンには aria-label で『前へ』『次へ』を、ドットには『スライド N』を付けており、スクリーンリーダーでも操作対象が読み上げられる。ただし現状の実装には aria-roledescription="carousel" と現在位置のライブリージョン通知が無いため、追加するなら .cr-root に role="region" aria-roledescription="carousel" を付け、現在スライド番号を aria-live="polite" の非表示テキストで告知するとよい。自動再生を足す場合は必ず一時停止ボタンを表示し、prefers-reduced-motion: reduce では自動送りそのものを止める(スワイプ・矢印操作は残す)。キーボード操作は現状ポインターイベントのみなので、矢印ボタンはTab移動できても左右矢印キーでスライドを送る機能は無く、追加するなら track に keydown ハンドラを補う必要がある。

調整して使う

調整できるのはスライド数・自動再生の有無・スワイプのしきい値(現在40px)。ページ全体のヒーロー用途なら高さを大きく取り、商品一覧の一部として使うなら複数枚同時表示(flex-basisを50%や33%にして一部を見切れさせる)にすると『まだ続きがある』ことが伝わりやすい。ドットは枚数が多い(8枚以上)と横に長くなりすぎるので、その場合は現在ページ数のテキスト表示(1/8)に切り替えるとよい。矢印を非表示にしてスワイプのみにするミニマルな構成も選べるが、その場合はPCユーザーのために必ずドットかテキスト表示を残し、操作手段をスワイプだけに絞らない。スワイプのしきい値40pxはトラックパッドの誤操作を拾いやすいので、対象がスマホ中心なら60〜80px程度に上げると意図しない送りが減る。

コード(コピーして使えます)

<div class="cr-root">
  <div class="cr-track" id="crTrack">
    <!-- <img src="..." alt="..."> を .cr-slide に置き換えて使う -->
    <div class="cr-slide" style="background:linear-gradient(135deg,#2b50c7 0%,#5a7bff 100%)">
      <span class="cr-label">スライド 1</span>
    </div>
    <div class="cr-slide" style="background:linear-gradient(135deg,#e86c4d 0%,#f5a623 100%)">
      <span class="cr-label">スライド 2</span>
    </div>
    <div class="cr-slide" style="background:linear-gradient(135deg,#2dc793 0%,#2b50c7 100%)">
      <span class="cr-label">スライド 3</span>
    </div>
    <div class="cr-slide" style="background:linear-gradient(135deg,#9b59b6 0%,#e86c4d 100%)">
      <span class="cr-label">スライド 4</span>
    </div>
  </div>
  <button class="cr-btn cr-prev" id="crPrev" aria-label="前へ">&#8249;</button>
  <button class="cr-btn cr-next" id="crNext" aria-label="次へ">&#8250;</button>
  <div class="cr-dots" id="crDots"></div>
</div>

タグ

同じカテゴリ「メディア・画像」のほかのパーツ

関連パーツ