コピペで簡単!JavaScriptとCSSで作る3Dサイコロ抽選アニメーション

Webサイトに「動き」を!CSSとJSで作る3Dサイコロ抽選アニメーション

こんにちは、「インターライフメディア ブログ」です。静的なWebサイトも良いですが、ユーザーの目を引くインタラクティブな要素(動き)を加えることで、サイトの印象はガラッと変わります。

特にキャンペーンページやイベント告知などで、「抽選」の仕組みがあると盛り上がりますよね。

今回は、Web制作者や学習中の方がコピペしてすぐ使える、CSSの3D表現とJavaScriptの配列処理を組み合わせた「3Dサイコロ抽選アニメーション」の実装方法を、コード付きで分かりやすく解説します。

完成デモ

まずは完成イメージをご覧ください。「サイコロを振る」ボタンを押すとアニメーションが始まり、「とめる」ボタンで配列(今回は人の名前)からランダムに1つを選んで表示します。一度選ばれた要素は、配列から削除される仕組みです。

実装コード全体

実装に必要なコードは「HTML」「SCSS (CSS)」「JavaScript」の3つです。今回のJavaScriptはjQueryを使用しているため、別途jQuery本体を読み込んでおく必要があります。

HTMLコード

構造は非常にシンプルです。サイコロの各面となる .item と、操作ボタン .js-dice を配置します。

<div id="wrap">
	<div class="stage">
		<div class="dice">
			<div class="item">1</div>
			<div class="item -main">2</div>
			<div class="item">3</div>
			<div class="item">4</div>
			<div class="item">5</div>
			<div class="item">6</div>
		</div>
	</div>
	<div class="button_wrap">
		<button class="js-dice">サイコロを振る</button>
	</div>
	<p class="leftovers-caption">【残りの値】</p>
	<div id="leftovers"></div>
</div>

SCSS (CSS) コード

サイコロの3D表現とアニメーションを定義します。SCSSを使用していますが、ネスト(入れ子)を解除すれば通常のCSSとしても機能します。

/* サイコロ本体 */
.dice {
	display:block;
	position:relative;
	margin:0 auto;
	width:100px;
	height:100px;
	transform-style:preserve-3d;
}
/* 目 */
.dice .item {
	border-radius: 3px;
	position:absolute;
	left:0;
	right:0;
	display:flex;
	flex-direction:row;
	align-items:center;
	justify-content:center;
	box-sizing:border-box;
	border:1px solid #333;
	width:100px;
	height:100px;
	background-color:rgba(#005bac, 0.7);
	font-size:2rem;
	text-align:center;
	color:#fff;
	&:nth-child(1) {
		transform:translate3d(0, -50px, 0) rotateX(-90deg);
	}
	//rotateがないのが正面
	&:nth-child(2) {
		transform:translate3d(0, 0, 50px);
	}
	&:nth-child(3) {
		transform:translate3d(50px, 0, 0) rotateY(90deg);
	}
	&:nth-child(4) {
		transform:translate3d(-50px, 0, 0) rotateY(-90deg);
	}
	&:nth-child(5) {
		transform:translate3d(0, 0, -50px) rotateY(180deg);
	}
	&:nth-child(6) {
		transform:translate3d(0, 50px, 0) rotateX(-90deg);
	}
}

//回転アニメーション:遠近
@keyframes rotate-animation {
	0% { transform:rotate3d(0); }
	100% { transform:rotate3d(0.5,0.75,0.5, 360deg); }
}
@keyframes rotate-animation1 {
	0% { transform:rotate3d(0); }
	100% { transform:rotate3d(1,0,1, -360deg); }
}
@keyframes rotate-animation2 {
	0% { transform:rotate3d(0); }
	100% { transform:rotate3d(0,1,1, -360deg); }
}
//ストップモーションアニメーション
@keyframes stopmotion {
	0% { transform:scale(0.5); }
	50% { transform:scale(1.2); }
	100% { transform:scale(1); }
}

//その他
#wrap {
	padding: 0 0 80px;
}
.stage {
  margin: 60px auto;
	perspective: 300px;
	transition: transform 0s;
	.dice {
		animation:rotate-animation 10s linear infinite;
		//サイコロを斜めに
		//transform:rotateX(-25deg) rotateY(-45deg);
	}
	//アニメ中style
	&.animation {
		transition: transform .3s;
		transform: scale(0.5);
		.dice {
			transform: none;
			animation:rotate-animation1 .3s linear infinite;
		}
		&.plus .dice{
			animation:rotate-animation2 .3s linear infinite;
		}
	}
	//結果画面
	&.stop {
		animation: stopmotion .2s both;
		.dice {
			transform: none;
			animation: none;
			.item.-main {
				//結果画面の背景画像変えるなら
				//background-color:rgba(0, 30, 30, 0.5);
			}
		}
	}
}
//ボタン
.button_wrap {
	margin-top: 60px;
	text-align: center;
	button {
		cursor: pointer;
	}
}

//配列の中身
.leftovers-caption {
	margin-top: 2em;
	text-align: center;
}
#leftovers {
  margin: 0 auto 2em;
  text-align: center;
}

JavaScript (jQuery) コード

ボタンのクリックイベントを監視し、CSSのクラスを付け替えることでアニメーションを制御します。抽選ロジックがメインです。

//settimeout用変数
var timerId;

//結果用配列
var resultArray = [
	"佐藤",
	"鈴木",
	"田中",
	"渡辺",
	"山本",
	"★"
]

//HTMLに配列の値を追加
for (var key in resultArray) {
	var num = parseInt(key) + 1;
  $('.dice .item:nth-child('+num+')').text(resultArray[key]);
}

//配列の値を指定のIDにテキストとして追加
$('#leftovers').text(JSON.stringify(resultArray));


//配列の値の数を取得
//オブジェクト(連想配列)の時の撮り方 → var res = Object.keys(resultArray).length;
var res = resultArray.length;

$('.js-dice').on('click',function(){

	//配列の残りの数が0以上なら実行
	if(res > 0) {

		//アニメーション中にボタンが押されたら
		if($(this).hasClass('start')) {
			//class="animation"を除去してclass="stop"を追加
			$('.stage').removeClass('animation').addClass('stop');
			//ボタンからもclass="start"を除去して、テキスト変更
			$(this).removeClass('start').text('サイコロを振る');
			//setIntervalを解除
			window.clearInterval(timerId);
			//サイコロの目のテキストを変更
			let saikoro = Math.floor( Math.random() * res) +1;
			$('.-main').text(resultArray[saikoro - 1]);

			//サイコロででた値を配列から削除
			res = res - 1;
			resultArray.splice( saikoro - 1, 1 );

			//値の減った配列の値をテキストにして出力
			$('#leftovers').text(JSON.stringify(resultArray));

			//配列に何も残ってなかったらボタンのテキストを変更
			if(res == 0) {
				$(this).removeClass('start').text('本日の抽選は以上です');
			}

		//アニメが停止中にボタンが押されたら
		} else {

				//class="stop"を除去してclass="animation"を追加
				$('.stage').addClass('animation').removeClass('stop');
				//ボタンにclass="start"を追加して、テキスト変更
				$(this).addClass('start').text('とめる');
				//サイコロの動きに変化をつけるようsetIntervalでclassを付け替え
				timerId = setInterval(function() {
					$('.stage').toggleClass('plus');
				}, 500);

		}
	}

});

コードのポイント解説

この実装には、Web制作初心者がつまずきやすいポイントがいくつか含まれています。特に重要な2点を解説します。

1. CSSによる3D空間の構築

サイコロが立体的に見えるのは、CSSの transform 関連のプロパティのおかげです。

  • perspective: 300px;(.stage): これが「視点」の役割を果たします。この値(奥行き)がないと、3Dの表現はただの平面的な変形(2D)に見えてしまいます。親要素に指定するのがポイントです。
  • transform-style: preserve-3d;(.dice): これが「3D空間」を宣言するプロパティです。子要素(.item)の3D変形を有効にし、立体的な配置を維持します。
  • transform: translate3d(...) rotateX(...)(.item): 各面を `translate3d` で移動させ、`rotateX` や `rotateY` で回転させることで、立方体の6面を組み立てています。

2. JavaScriptによる抽選ロジック

JavaScriptは、アニメーションの制御と抽選処理を担当しています。

  • クラスの付け替え: .js-dice ボタンをクリックするたびに、.stage 要素の .animation クラスと .stop クラスを付け替えています。CSS側では、このクラスの有無で @keyframes アニメーションを再生したり停止したりしています。
  • Math.floor( Math.random() * res) + 1: JavaScriptでランダムな整数を生成する定番の記述です。Math.random()(0以上1未満の小数)に配列の現在の長さ(res)を掛け、切り捨てることで「0から(res-1)まで」のインデックス番号を取得しています。
  • resultArray.splice( saikoro - 1, 1 ): splice メソッドは、配列から指定した要素を「削除」するために使います。これにより、一度当選したものが再度抽選されない「重複なし」の抽選を実現しています。

まとめ

今回は、CSSの3D表現とJavaScriptの配列処理を組み合わせた、インタラクティブな抽選アニメーションをご紹介しました。

resultArray の中身を商品名に変えればキャンペーンの抽選機になりますし、CSSの背景色や @keyframes の内容を変更すれば、オリジナルのアニメーションにカスタマイズできます。ぜひあなたのWebサイトにも、遊び心のある「動き」を取り入れてみてください。


よくある質問(FAQ)

Q1. サイコロの面を数字やテキストではなく、画像に差し替えることはできますか?

A1. はい、可能です。HTMLの <div class="item">テキスト</div> の中身を、<img src="..." alt="..."> タグに置き換えるのが最も簡単です。ただし、.item に指定しているCSS(display: flex など)が画像の表示に影響する場合があります。その際は、.itembackground-image プロパティを使って背景画像として設定する方法もおすすめです。

Q2. 抽選対象(配列の中身)を動的に変更することは可能ですか?

A2. はい、可能です。今回のサンプルコードでは resultArray がJavaScriptファイル内に直接書き込まれていますが、例えばPHPやデータベースと連携し、サーバーから抽選対象のリスト(JSON形式など)を取得して resultArray に代入するロジックに変更すれば、動的な抽選システムを構築できます。

Q3. CSSの preserve-3d がうまく効かず、サイコロが立体的に見えません。

A3. 3D表現でつまずく最も一般的な原因は、親要素に perspective が指定されていないことです。サイコロ本体(.dice)の親要素である .stage に、perspective: 300px; のような奥行きを指定しているか確認してください。また、.dice 自身に transform-style: preserve-3d; が指定されているかも併せてご確認ください。

CONTACT

webサイト制作、デザインに関するご相談、御見積のご依頼など、弊社へのお問い合わせはこちら