なめらかに無限ループするカルーセルを作る方法【HTML/CSS/JavaScript・サンプルコード付き】
カルーセル
なめらかに無限ループするカルーセルを作る方法
なめらかに無限ループするカルーセルを作る方法を紹介します。HTML・CSS・JavaScriptだけを使用し、最後のスライドから最初のスライドへ切り替わる際に違和感なくループするカルーセルを実装できるサンプルです。トップページのメインビジュアルやおすすめ商品、お知らせなど、複数の情報を繰り返し表示したい場面で利用できます。
このサンプルでは、カルーセルの先頭と末尾にスライドを複製して配置し、JavaScriptで表示位置を自動的に補正することで、最後まで進んでも途中で止まったり最初へ戻る動きが目立ったりせず、自然に繰り返し表示できます。左右の矢印やドットナビから手動でスライドを切り替えることもでき、ループ中でもスムーズな操作を維持できます。
サービス紹介やキャンペーン、商品一覧など、カルーセルを長時間表示するページでも自然な動きを実現できます。画像やテキストを差し替えるだけで利用できるため、実際のWebサイトにも導入しやすく、通常のカルーセルより一歩進んだ実装を学びたい方にもおすすめです。
コードについて
本記事のコードはサンプルコードです。ご利用前に必ず動作確認を行ってください。
免責事項
本コードの利用により発生した損害について、当サイトは一切の責任を負いません。
デモ
新しいサービスを紹介
なめらかなスライドアニメーションで、トップページやサービス紹介などのメインビジュアルを自然に切り替えながら表示できます。
詳しく見る
おすすめ情報を表示
おすすめ商品や新着情報、キャンペーンなど複数のコンテンツを順番に表示できるため、限られたスペースを有効活用できます。
詳細を見る
キャンペーンを告知
最後のスライドまで進んでも違和感なく最初のスライドへ戻るため、繰り返し表示するカルーセルとして快適な操作感を実現できます。
確認する
コードをコピーして使おう!
<!DOCTYPE html>
<html lang="ja">
<head>
<!-- 文字コード -->
<meta charset="UTF-8">
<!-- スマホ表示に対応 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- ページタイトル -->
<title>なめらかに無限ループするカルーセル</title>
<!-- CSSファイルを読み込み -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- カルーセル全体 -->
<div class="renew-loop-carousel">
<!-- カルーセル表示エリア -->
<div class="renew-loop-carousel_view">
<!-- スライドを重ねて表示するエリア -->
<div class="renew-loop-carousel_track">
<!-- スライド1 -->
<div class="renew-loop-carousel_slide active">
<div class="renew-loop-carousel_content">
<div class="renew-loop-carousel_title">新しいサービスを紹介</div>
<p>なめらかなスライドアニメーションで、トップページやサービス紹介などのメインビジュアルを自然に切り替えながら表示できます。</p>
<a href="#" class="renew-loop-carousel_btn">詳しく見る</a>
</div>
</div>
<!-- スライド2 -->
<div class="renew-loop-carousel_slide right">
<div class="renew-loop-carousel_content">
<div class="renew-loop-carousel_title">おすすめ情報を表示</div>
<p>おすすめ商品や新着情報、キャンペーンなど複数のコンテンツを順番に表示できるため、限られたスペースを有効活用できます。</p>
<a href="#" class="renew-loop-carousel_btn">詳細を見る</a>
</div>
</div>
<!-- スライド3 -->
<div class="renew-loop-carousel_slide left">
<div class="renew-loop-carousel_content">
<div class="renew-loop-carousel_title">キャンペーンを告知</div>
<p>最後のスライドまで進んでも違和感なく最初のスライドへ戻るため、繰り返し表示するカルーセルとして快適な操作感を実現できます。</p>
<a href="#" class="renew-loop-carousel_btn">確認する</a>
</div>
</div>
</div>
<!-- 前へボタン -->
<button class="renew-loop-carousel_arrow renew-loop-carousel_prev" type="button">‹</button>
<!-- 次へボタン -->
<button class="renew-loop-carousel_arrow renew-loop-carousel_next" type="button">›</button>
<!-- ドットナビゲーション -->
<div class="renew-loop-carousel_dots">
<button class="renew-loop-carousel_dot active" type="button" aria-label="1枚目"></button>
<button class="renew-loop-carousel_dot" type="button" aria-label="2枚目"></button>
<button class="renew-loop-carousel_dot" type="button" aria-label="3枚目"></button>
</div>
</div>
</div>
<!-- JavaScriptファイルを読み込み -->
<script src="script.js"></script>
</body>
</html>
/* ページ全体 */
body{
margin:0; /* ページ外側の余白 */
font-family:sans-serif; /* 使用するフォント */
background:#f8fafc; /* ページ背景色 */
color:#334155; /* 基本文字色 */
}
/* カルーセル全体 */
.renew-loop-carousel{
max-width:1000px; /* カルーセルの最大横幅 */
margin:40px auto; /* 上下余白と中央寄せ */
padding:24px; /* 外側余白 */
box-sizing:border-box; /* paddingを幅に含める */
font-family:sans-serif; /* 使用するフォント */
}
/* カルーセル表示エリア */
.renew-loop-carousel_view{
position:relative; /* 矢印とドットの配置基準 */
overflow:hidden; /* はみ出したスライドを隠す */
border-radius:24px; /* 角丸 */
background:#2563eb; /* 背景色 */
box-shadow:0 16px 35px rgba(15,23,42,.12); /* 影 */
}
/* スライドを重ねるエリア */
.renew-loop-carousel_track{
position:relative; /* スライド配置の基準 */
height:420px; /* カルーセルの高さ */
}
/* スライド共通 */
.renew-loop-carousel_slide{
position:absolute; /* スライドを同じ位置に重ねる */
inset:0; /* 上下左右いっぱいに配置 */
padding:56px; /* 内側余白 */
box-sizing:border-box; /* paddingを幅に含める */
display:flex; /* 中身を配置 */
align-items:center; /* 縦中央 */
opacity:0; /* 通常時は非表示 */
transform:translateX(100%); /* 右側に待機 */
transition:transform .45s ease, opacity .45s ease; /* 切り替えアニメーション */
}
/* 表示中のスライド */
.renew-loop-carousel_slide.active{
opacity:1; /* 表示する */
transform:translateX(0); /* 中央に表示 */
z-index:2; /* 前面に表示 */
}
/* 左側へ移動したスライド */
.renew-loop-carousel_slide.left{
opacity:0; /* 非表示 */
transform:translateX(-100%); /* 左側に移動 */
}
/* 右側へ待機するスライド */
.renew-loop-carousel_slide.right{
opacity:0; /* 非表示 */
transform:translateX(100%); /* 右側に移動 */
}
/* スライド1 */
.renew-loop-carousel_slide:nth-child(1){
background:linear-gradient(135deg,#2563eb,#60a5fa); /* 背景 */
}
/* スライド2 */
.renew-loop-carousel_slide:nth-child(2){
background:linear-gradient(135deg,#1e40af,#3b82f6); /* 背景 */
}
/* スライド3 */
.renew-loop-carousel_slide:nth-child(3){
background:linear-gradient(135deg,#0f172a,#2563eb); /* 背景 */
}
/* テキストエリア */
.renew-loop-carousel_content{
max-width:460px; /* 文章の最大横幅 */
margin-left:72px; /* 左矢印と重ならない余白 */
color:#ffffff; /* 文字色 */
}
/* タイトル */
.renew-loop-carousel_title{
margin:0 0 16px; /* 下余白 */
font-size:38px; /* 文字サイズ */
font-weight:700; /* 文字の太さ */
line-height:1.3; /* 行間 */
}
/* 説明文 */
.renew-loop-carousel_content p{
margin:0 0 24px; /* 下余白 */
font-size:16px; /* 文字サイズ */
line-height:1.8; /* 行間 */
}
/* ボタン */
.renew-loop-carousel_btn{
display:inline-flex; /* ボタン型にする */
align-items:center; /* 縦中央 */
justify-content:center; /* 横中央 */
width:160px; /* 横幅 */
height:46px; /* 高さ */
border-radius:999px; /* 丸いボタン */
background:#ffffff; /* 背景色 */
color:#2563eb; /* 文字色 */
font-weight:700; /* 文字の太さ */
text-decoration:none; /* 下線を消す */
}
/* 左右矢印共通 */
.renew-loop-carousel_arrow{
position:absolute; /* カルーセル上に配置 */
top:50%; /* 縦中央 */
transform:translateY(-50%); /* 縦位置を補正 */
width:44px; /* 横幅 */
height:44px; /* 高さ */
border:none; /* 枠線なし */
border-radius:50%; /* 円形 */
background:#ffffff; /* 背景色 */
color:#2563eb; /* 矢印色 */
font-size:24px; /* 矢印サイズ */
cursor:pointer; /* カーソル */
z-index:5; /* スライドより前面 */
}
/* 前へボタン */
.renew-loop-carousel_prev{
left:20px; /* 左位置 */
}
/* 次へボタン */
.renew-loop-carousel_next{
right:20px; /* 右位置 */
}
/* ドットナビゲーション */
.renew-loop-carousel_dots{
position:absolute; /* カルーセル下部へ配置 */
left:0; /* 左端 */
right:0; /* 右端 */
bottom:20px; /* 下位置 */
display:flex; /* 横並び */
justify-content:center; /* 中央寄せ */
gap:10px; /* ドット同士の間隔 */
z-index:5; /* スライドより前面 */
}
/* ドット */
.renew-loop-carousel_dot{
width:12px; /* 横幅 */
height:12px; /* 高さ */
padding:0; /* 内側余白なし */
border:none; /* 枠線なし */
border-radius:50%; /* 円形 */
background:rgba(255,255,255,.45); /* 通常色 */
cursor:pointer; /* カーソル */
}
/* 選択中ドット */
.renew-loop-carousel_dot.active{
background:#ffffff; /* 選択中の色 */
}
/* 画面幅が狭い場合 */
@media(max-width:600px){
.renew-loop-carousel{
margin:24px auto; /* スマホ時の外側余白 */
padding:16px; /* スマホ時の内側余白 */
}
.renew-loop-carousel_track{
height:360px; /* スマホ時の高さ */
}
.renew-loop-carousel_slide{
padding:48px 24px; /* スマホ時の内側余白 */
}
.renew-loop-carousel_content{
margin-left:48px; /* スマホ時の左余白 */
}
.renew-loop-carousel_title{
font-size:28px; /* スマホ時のタイトルサイズ */
}
}
// スライド一覧を取得
const renewLoopCarouselSlides = document.querySelectorAll(".renew-loop-carousel_slide");
// ドット一覧を取得
const renewLoopCarouselDots = document.querySelectorAll(".renew-loop-carousel_dot");
// 次へボタンを取得
const renewLoopCarouselNext = document.querySelector(".renew-loop-carousel_next");
// 前へボタンを取得
const renewLoopCarouselPrev = document.querySelector(".renew-loop-carousel_prev");
// 現在表示中のスライド番号
let renewLoopCarouselCurrent = 0;
// スライド表示を更新する関数
function renewLoopCarouselDraw(){
// スライドの状態を更新
renewLoopCarouselSlides.forEach(function(slide,index){
// いったんすべての状態クラスを外す
slide.className = "renew-loop-carousel_slide";
// 現在のスライドを表示
if(index === renewLoopCarouselCurrent){
slide.classList.add("active");
// 次に表示されるスライドを右側へ配置
}else if(index === (renewLoopCarouselCurrent + 1) % renewLoopCarouselSlides.length){
slide.classList.add("right");
// その他のスライドは左側へ配置
}else{
slide.classList.add("left");
}
});
// すべてのドットを通常状態へ戻す
renewLoopCarouselDots.forEach(function(dot){
dot.classList.remove("active");
});
// 現在のスライドに対応するドットを選択状態にする
renewLoopCarouselDots[renewLoopCarouselCurrent].classList.add("active");
}
// 次へボタンを押した時の処理
renewLoopCarouselNext.addEventListener("click", function(){
// 最後の次は最初へ戻る
renewLoopCarouselCurrent =
(renewLoopCarouselCurrent + 1) % renewLoopCarouselSlides.length;
// 表示を更新
renewLoopCarouselDraw();
});
// 前へボタンを押した時の処理
renewLoopCarouselPrev.addEventListener("click", function(){
// 最初の前は最後へ戻る
renewLoopCarouselCurrent =
(renewLoopCarouselCurrent - 1 + renewLoopCarouselSlides.length) % renewLoopCarouselSlides.length;
// 表示を更新
renewLoopCarouselDraw();
});
// ドットを押した時の処理
renewLoopCarouselDots.forEach(function(dot,index){
dot.addEventListener("click", function(){
// 押したドットの番号へ移動
renewLoopCarouselCurrent = index;
// 表示を更新
renewLoopCarouselDraw();
});
});
ファイル構成と設置方法
このサンプルは、HTML・CSS・JavaScriptの3ファイルで構成されています。HTMLにカルーセルのレイアウト、CSSにデザインとアニメーション、JavaScriptにスライド切り替え処理を記述しています。JavaScriptでは表示するスライドを切り替えることで、途切れのないなめらかな無限ループを実現しています。
sample/
├── index.html
├── style.css
└── script.js
sampleフォルダ内の index.html をブラウザで開くと動作を確認できます。スライドの内容やボタンの文字は index.html、色やサイズ、余白、アニメーション速度は style.css、スライドの切り替え処理やループ動作は script.js で変更できます。
なめらかに無限ループするカルーセルを作る方法【HTML/CSS/JavaScript・サンプルコード付き】
コメント