CSSとJavaScriptで作る3Dカルーセル|キーボード操作対応のインタラクティブギャラリー


Webサイトに奥行きと立体感を与える3Dカルーセル。単なる平面的なスライダーとは違い、空間の中でカードが回転する様子は、ユーザーに印象的な体験を提供します。

この記事では、CSS 3D transformsとJavaScriptを使って、キーボード操作にも対応した本格的な3Dカルーセルの作り方を解説します。

差分チェックツールで効率UPお手本コードと自分のコードを比較して、違いを一目で確認できます。練習前にブックマークしておくと便利です。
Diff Checkerを開く →

See the Pen Untitled by masakazuimai (@masakazuimai) on CodePen.

今回作成する3Dカルーセルは、以下の機能を備えています。3D空間でのカード回転、左右矢印キーでのナビゲーション、スペースキーでの自動再生と停止の切り替え、スムーズなトランジション効果、そして中央にフォーカスした見やすいレイアウトです。


CSS 3D Transformsの基礎

3Dカルーセルを実装する前に、CSS 3D transformsの重要な概念を押さえておきましょう。

perspectiveプロパティ

perspectiveは、3D空間の「視点」を設定するプロパティです。この値が小さいほど視点が近く、大きいほど遠くから見ている状態になります。今回の実装では、カルーセルコンテナに1200pxのperspectiveを設定しています。

perspectiveは通常、3D変形を行う要素の親要素に設定します。値は800pxから2000pxの範囲が一般的で、1200px前後が自然な立体感を生み出します。値が小さすぎると歪みが強くなり、大きすぎると立体感が弱くなってしまいます。

transform-style: preserve-3d

transform-style: preserve-3dは、子要素の3D変形を保持するために必須のプロパティです。カルーセル要素にこのプロパティを設定することで、カード要素が3D空間内で正しく配置されます。

このプロパティがないと、子要素は平面的にレンダリングされてしまい、せっかくの3D効果が失われてしまいます。3D transformsを使う際は、必ずこのプロパティを親要素に設定することを忘れないようにしましょう。

rotateY()による回転

rotateY()は、Y軸、つまり縦軸を中心に要素を回転させる関数です。3Dカルーセルでは、この回転を動的に変化させることで、カードが円形に配置されているように見せます。

各カードに異なる角度のrotateYを適用することで、円周上に並んだ配置を実現しています。

<div class="scene">
  <div class="carousel">
    <div class="carousel__cell">01 / 06</div>
    <div class="carousel__cell">02 / 06</div>
    <div class="carousel__cell">03 / 06</div>
    <div class="carousel__cell">04 / 06</div>
    <div class="carousel__cell">05 / 06</div>
    <div class="carousel__cell">06 / 06</div>
  </div>
</div>
/* 3D空間の視点を決める親要素 */
.scene {
  width: 320px;
  height: 400px;
  perspective: 1200px;
  position: relative;
}

/* 子要素の3D変形を保持し、回転をアニメーションさせる */
.carousel {
  width: 100%;
  height: 100%;
  position: absolute;
  transform-style: preserve-3d;
  transition: transform 0.8s cubic-bezier(0.23, 1, 0.32, 1);
}

/* 各カードは絶対配置。裏面は非表示にしておく */
.carousel__cell {
  position: absolute;
  width: 280px;
  height: 380px;
  left: 20px;
  top: 10px;
  backface-visibility: hidden;
}

3Dカルーセルの実装ポイント

カードの円形配置

3Dカルーセルの核心は、カードを円周上に配置することです。5枚のカードを均等に配置する場合、360度を5で割った72度ずつ回転させます。

1枚目はrotateY(0deg)、2枚目はrotateY(72deg)、3枚目はrotateY(144deg)、4枚目はrotateY(216deg)、5枚目はrotateY(288deg)という具合に配置します。

JavaScriptで動的に設定する場合は、360度をカード総数で割った値に、各カードのインデックスを掛けることで角度を計算できます。

translateZで奥行きを調整

translateZ()は、回転させた要素を視点から離す、または近づける役割を果たします。この値が大きいほどカルーセルの半径が大きくなります。今回の実装では、400pxの値を使用しています。

重要なのは、rotateY()の後にtranslateZ()を適用する順序です。この順序により、回転後にZ軸方向へ移動することで円形配置が実現されます。順序を逆にすると、意図した配置にならないので注意が必要です。

const carousel = document.querySelector(".carousel");
const cells = carousel.querySelectorAll(".carousel__cell");
const cellCount = cells.length;

// 1枚あたりのステップ角度(6枚なら60度)
const theta = 360 / cellCount;

// カード幅280pxから半径を算出。+80pxでカード同士の間隔を確保する
const radius = Math.round(280 / 2 / Math.tan(Math.PI / cellCount)) + 80;

function setupCarousel() {
  cells.forEach((cell, i) => {
    // rotateY で向きを決めてから translateZ で外周へ押し出す(順序が重要)
    cell.style.transform = `rotateY(${theta * i}deg) translateZ(${radius}px)`;
  });
}

JavaScriptでの回転制御

回転ロジックの実装

カルーセル全体を回転させるには、コンテナ要素のrotateYの値を変更します。現在の回転角度を変数で管理し、ユーザーの操作に応じて角度を加算または減算していきます。

1枚分のステップ角度は、カード総数から計算します。5枚のカルーセルなら72度がステップ角度になります。左ボタンをクリックすると角度がプラス、右ボタンをクリックすると角度がマイナスされることで、カルーセルが回転します。

このシンプルなロジックで、カルーセルをスムーズに回転させることができます。

let selectedIndex = 0;
let currentAngle = 0;

function rotateCarousel(steps = 0) {
  currentAngle -= steps * theta;
  // カルーセル全体を手前に引き戻してから回転させる
  carousel.style.transform = `translateZ(${-radius}px) rotateY(${currentAngle}deg)`;
}

スムーズなアニメーション

CSSトランジションを使うことで、回転がスムーズになります。transitionプロパティにtransformを指定し、0.8秒程度の時間とイージング関数を設定します。

イージング関数には、cubic-bezier(0.23, 1, 0.32, 1)を使用しています。これは、終盤にかけて滑らかに減速する自然な動きを作り出す関数です。単純なease-in-outよりも洗練された動きになります。

カウンター管理

現在表示されているカードを追跡するために、インデックスを管理します。ユーザーが左右に操作するたびに、このインデックスを更新します。

モジュロ演算子を使うことで、インデックスが範囲外になることを防ぎます。たとえば、5枚のカルーセルで右端から右に進むと、自動的に左端に戻ります。負の値になった場合も、カード総数を加算することで正しい範囲に収めます。


キーボード操作の実装

イベントリスナーの設定

キーボード操作を実装するには、keydownイベントを監視します。ユーザーが左矢印キーを押したとき、右矢印キーを押したとき、スペースキーを押したときに、それぞれ異なる処理を実行します。

左矢印キーでは、カルーセルを右方向に回転させ、インデックスを1つ減らします。右矢印キーでは逆に、左方向に回転させ、インデックスを1つ増やします。スペースキーでは、自動再生機能の開始と停止を切り替えます。

スペースキーのデフォルト動作、つまりページスクロールを防ぐために、preventDefault()を呼び出すことも忘れないようにしましょう。

document.addEventListener("keydown", (e) => {
  if (e.key === "ArrowLeft") {
    selectedIndex = (selectedIndex - 1 + cellCount) % cellCount;
    rotateCarousel(-1);
  } else if (e.key === "ArrowRight") {
    selectedIndex = (selectedIndex + 1) % cellCount;
    rotateCarousel(1);
  } else if (e.key === " ") {
    e.preventDefault(); // スペースキーによるページスクロールを防ぐ
    toggleAutoPlay();
  }
});

自動再生機能

一定間隔で自動的に回転させる機能も実装しています。setInterval()を使うことで、指定した間隔で関数を実行できます。今回は3秒ごとに自動で次のカードに進むように設定しています。

自動再生中かどうかを示すフラグを用意し、スペースキーで切り替えられるようにしています。再生中にスペースキーを押すとclearInterval()でインターバルをクリアし、停止します。停止中にスペースキーを押すと、新しいインターバルを設定して再生を開始します。

この機能により、ユーザーが自分のペースでコンテンツを閲覧できます。

let autoPlayInterval = null;
let isPlaying = false;

function toggleAutoPlay() {
  if (isPlaying) {
    clearInterval(autoPlayInterval);
  } else {
    autoPlayInterval = setInterval(() => {
      selectedIndex = (selectedIndex + 1) % cellCount;
      rotateCarousel(1);
    }, 3000);
  }
  isPlaying = !isPlaying;
}

カスタマイズのポイント

カード枚数の変更

カード枚数を変更する場合は、カード総数とステップ角度を調整します。たとえば7枚に変更する場合、360度を7で割った約51.43度がステップ角度になります。

カード枚数が増えるほど、translateZ()の値を大きくすることで、カード同士の重なりを防げます。カードのサイズとカルーセルの半径のバランスを調整することが重要です。

回転速度の調整

トランジションの時間を変更することで、回転速度を調整できます。ゆっくりとした回転にしたい場合は1秒以上、素早い回転にしたい場合は0.3秒程度に設定します。

イージング関数も変更することで、動きの印象を大きく変えられます。ease-in-outでは滑らかな動き、ease-outでは最初速く後でゆっくりな動きになります。

背景エフェクトの追加

中央のカードを強調するために、背景にグロー効果を追加することもできます。カルーセル要素の疑似要素を使い、radial-gradientで円形のグラデーションを作成します。

pointer-events: noneを設定することで、この背景エフェクトがクリック操作を妨げないようにできます。グロー効果の大きさや透明度を調整することで、デザインに合わせたカスタマイズが可能です。

ここまでのカスタマイズをコードで詰めるのが手間な場合は、カード枚数や回転速度をGUIで指定してコードを取得できる3Dカルーセルをコピペで作る無料ツールも用意しています。こちらはGSAPで動く6タイプから選ぶ構成なので、本記事の素のCSS+JavaScript実装とは別のアプローチとして使い分けてください。


まとめ

CSS 3D transformsとJavaScriptを組み合わせることで、インタラクティブな3Dカルーセルを実装できます。

重要なポイントは3つです。第一に、perspectiveとtransform-style: preserve-3dで3D空間を作ること。第二に、rotateY()とtranslateZ()でカードを円形に配置すること。第三に、JavaScriptで回転ロジックとキーボード操作を実装することです。

この3Dカルーセルは、ポートフォリオサイトやプロダクト紹介ページなど、視覚的なインパクトが求められる場面で活用できます。ぜひカスタマイズして、オリジナルのインタラクティブギャラリーを作ってみてください。


よくある質問(FAQ)

Q. CSSだけで3Dカルーセルは作れますか?

CSS transformのrotateYやtranslateZプロパティとperspectiveを組み合わせることで、3D空間でのカルーセル表現が可能です。ただし、ドラッグ操作やキーボード制御にはJavaScriptが必要になります。

Q. 3Dカルーセルのアクセシビリティ対応は?

キーボードの矢印キーで操作できるようにし、aria-roledescription=”carousel”とaria-label属性を設定してください。自動再生がある場合は一時停止ボタンを設置し、prefers-reduced-motionメディアクエリでアニメーションを無効化する対応も必要です。


関連記事

本のようなページめくりUIを実装する方法|ドラッグ操作で自然な操作感を作る