お気軽にお問い合わせください。
052-886-5989
Shopifyで簡単実装!商品カルーセルの無限ループを作るHTML・CSS・JS・liquidコード完全ガイド

Shopifyで商品の魅力を最大限に引き出すためには、カルーセル(スライダー)が非常に効果的なツールとなります。多くの商品をコンパクトかつ視覚的に表示できるため、ユーザーの購買意欲を高め、結果として売上向上に大きく寄与します。本記事では、無限ループする商品カルーセルを簡単に実装するためのHTML・CSS・JavaScriptのコードを詳しく紹介するとともに、導入時の注意点、具体的な使い方、そしてさらなる効果を生み出すカスタマイズ方法を解説します。
商品カルーセルとは?
商品カルーセルは、複数の商品画像を横方向にスライド表示できるUIコンポーネントのことです。商品ページやトップページなどに設置されることが多く、ユーザーにとって商品を直感的に閲覧しやすくします。また、限られたスペースで多くの商品をアピールできるため、特にECサイトにおいて効果的なデザイン手法です。

導入方法の手順
Shopifyのページ作成から作る方法
今回紹介するコードは、HTML・CSS・JavaScriptの3つの要素で構成されています。以下の手順で簡単にShopifyページに導入できます
Shopifyの管理画面から「オンラインストア」→「ページ」→「ページを追加」をクリックし、テーマの「コードを編集」を開き、HTMLを見るボタンを押す

コードエディタに下記コードを貼り付けて保存する。
※画像やリンク先、商品名などは変更してご使用ください。

ページを確認。スライドショーの挙動など確認してください。お使いの環境によってはうまく動作品場合がございます。

ページ作成の時の実際のサンプルコード
下記コードを張り付けてご使用ください。
下記箇所を変更してご利用ください。
①タイトル
<h2 class=”my-carousel-heading”> サンプル商品が並ぶカルーセル</h2>
②商品画像・商品名
<img src=”https://via.placeholder.com/300?text=Product+1″ alt=”サンプル商品1″>
③商品リンク
<a href=”#” class=”my-carousel-button”>詳細を見る</a>(#をリンク先に設定してください。)
④商品説明
<p class=”my-carousel-spec”>1個~注文OK<br></p>
⑤詳細ボタンの色
.my-carousel-button {background-color: #ff5722;}
⑥一覧ボタンの色
.view-all-button {background-color: #ff5722;}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>サンプル:無限ループのカルーセル</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
/****************************************
* (1) 全体スタイル
****************************************/
body {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: sans-serif;
background-color: #f5f5f5;
}
/* カルーセルをまとめるセクション */
.my-carousel-section {
position: relative;
width: 100vw; /* 幅をブラウザに合わせる */
left: 50%;
transform: translateX(-50%);
background-color: #e0e0e0;
padding: 60px 0;
box-sizing: border-box;
}
.my-carousel-wrapper {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
box-sizing: border-box;
}
.my-carousel-heading {
max-width: 700px;
margin: 0 auto;
font-weight: bold;
text-align: center;
font-size: 24px;
padding: 20px;
position: relative;
border-radius: 5px;
color: #515151;
margin-bottom: 30px;
}
/****************************************
* (2) カルーセル部分
****************************************/
.carousel-container {
position: relative;
margin: 0 auto;
overflow: hidden; /* スクロール領域外を隠す */
}
/* スムーズスクロール。ただし最初とジャンプ時だけOFFにするためのクラスと併用 */
.my-carousel-grid {
display: flex;
flex-wrap: nowrap;
gap: 30px;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
user-select: none;
cursor: grab;
scrollbar-width: none; /* Firefoxでスクロールバー非表示 */
-ms-overflow-style: none; /* IE/Edgeで非表示 */
scroll-behavior: smooth; /* スムーズスクロール */
box-sizing: border-box;
padding-bottom: 10px;
}
.my-carousel-grid::-webkit-scrollbar {
display: none; /* Chrome, Safari 等のスクロールバー非表示 */
}
.my-carousel-grid:active {
cursor: grabbing;
}
/* ジャンプ時だけスムーズスクロールをOFFにするためのクラス */
.no-scroll-transition {
scroll-behavior: auto !important;
}
/****************************************
* (3) カードデザイン
****************************************/
.my-carousel-item {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
transition: transform 0.3s ease, box-shadow 0.3s ease;
color: #333;
display: flex;
flex-direction: column;
align-items: center;
flex: 0 0 280px; /* 横幅(お好みで調整) */
margin-bottom: 0;
}
.my-carousel-item:hover {
transform: translateY(-3px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
.my-carousel-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
padding: 20px;
}
.my-carousel-image {
width: 250px;
height: 250px;
border-radius: 4px;
overflow: hidden;
flex-shrink: 0;
}
.my-carousel-image img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.my-carousel-info {
width: 100%;
text-align: center;
}
.my-carousel-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 6px;
color: #333;
}
.my-carousel-spec {
font-size: 14px;
color: #666;
margin-bottom: 6px;
line-height: 1.4;
font-weight: bold;
}
.my-carousel-price {
font-size: 22px;
font-weight: bold;
color: #ff5722;
}
.my-carousel-price .tax-included {
font-size: 0.6em;
vertical-align: baseline;
}
.my-carousel-button {
display: inline-block;
margin-top: 10px;
font-size: 14px;
font-weight: bold;
color: #fff !important;
background-color: #ff5722;
padding: 8px 16px;
border-radius: 4px;
text-decoration: none;
border: none;
cursor: pointer;
transition: opacity 0.2s ease;
}
.my-carousel-button:hover {
opacity: 0.9;
}
/****************************************
* (4) 左右矢印ボタン
****************************************/
.carousel-arrow {
position: absolute;
top: 50%;
z-index: 5;
transform: translateY(-50%);
background: rgba(0, 0, 0, 0.5);
color: #fff;
border: none;
width: 40px;
height: 40px;
cursor: pointer;
border-radius: 50%;
font-size: 20px;
}
.carousel-arrow.prev {
left: 10px;
}
.carousel-arrow.next {
right: 10px;
}
/****************************************
* (5) 下部ボタン部分 (任意)
****************************************/
.my-carousel-footer {
margin-top: 40px;
text-align: center;
line-height: 1.8;
font-size: 16px;
max-width: 800px;
margin-left: auto;
margin-right: auto;
}
.view-all-button {
display: inline-block;
background-color: #ff5722;
color: #fff !important;
font-size: 18px;
font-weight: bold;
padding: 12px 40px;
border-radius: 6px;
text-decoration: none;
margin-top: 20px;
transition: transform 0.1s ease-in-out, background-color 0.3s;
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
}
.view-all-button:hover {
background-color: #e64a19;
}
.view-all-button:active {
transform: scale(0.9);
box-shadow: inset 0 4px 6px rgba(0,0,0,0.2);
}
</style>
</head>
<body>
<!-- カルーセルセクション -->
<section class="my-carousel-section">
<div class="my-carousel-wrapper">
<h2 class="my-carousel-heading">
サンプル商品が並ぶカルーセル!
</h2>
<!-- カルーセル全体のラッパ -->
<div class="carousel-container">
<!-- 左ボタン -->
<button class="carousel-arrow prev">←</button>
<!-- スライド領域 -->
<!-- 初期ロード時は「no-scroll-transition」をつけてガタつきを防止 -->
<div class="my-carousel-grid no-scroll-transition" id="carousel">
<!-- 以下、サンプル商品カードを複数 (例では5個) 並べています -->
<div class="my-carousel-item">
<div class="my-carousel-content">
<div class="my-carousel-image">
<img src="https://via.placeholder.com/300?text=Product+1" alt="サンプル商品1">
</div>
<div class="my-carousel-info">
<h3 class="my-carousel-title">サンプル商品1</h3>
<p class="my-carousel-spec">
1個~注文OK<br>
フルカラー印刷
</p>
<p class="my-carousel-price">
<span class="tax-included">@</span>500円
<span class="tax-included">(税込)</span>
</p>
<a href="#" class="my-carousel-button">詳細を見る</a>
</div>
</div>
</div>
<div class="my-carousel-item">
<div class="my-carousel-content">
<div class="my-carousel-image">
<img src="https://via.placeholder.com/300?text=Product+2" alt="サンプル商品2">
</div>
<div class="my-carousel-info">
<h3 class="my-carousel-title">サンプル商品2</h3>
<p class="my-carousel-spec">
1個~注文OK<br>
フルカラー印刷
</p>
<p class="my-carousel-price">
<span class="tax-included">@</span>700円
<span class="tax-included">(税込)</span>
</p>
<a href="#" class="my-carousel-button">詳細を見る</a>
</div>
</div>
</div>
<div class="my-carousel-item">
<div class="my-carousel-content">
<div class="my-carousel-image">
<img src="https://via.placeholder.com/300?text=Product+3" alt="サンプル商品3">
</div>
<div class="my-carousel-info">
<h3 class="my-carousel-title">サンプル商品3</h3>
<p class="my-carousel-spec">
1個~注文OK<br>
フルカラー印刷
</p>
<p class="my-carousel-price">
<span class="tax-included">@</span>900円
<span class="tax-included">(税込)</span>
</p>
<a href="#" class="my-carousel-button">詳細を見る</a>
</div>
</div>
</div>
<div class="my-carousel-item">
<div class="my-carousel-content">
<div class="my-carousel-image">
<img src="https://via.placeholder.com/300?text=Product+4" alt="サンプル商品4">
</div>
<div class="my-carousel-info">
<h3 class="my-carousel-title">サンプル商品4</h3>
<p class="my-carousel-spec">
1個~注文OK<br>
フルカラー印刷
</p>
<p class="my-carousel-price">
<span class="tax-included">@</span>1200円
<span class="tax-included">(税込)</span>
</p>
<a href="#" class="my-carousel-button">詳細を見る</a>
</div>
</div>
</div>
<div class="my-carousel-item">
<div class="my-carousel-content">
<div class="my-carousel-image">
<img src="https://via.placeholder.com/300?text=Product+5" alt="サンプル商品5">
</div>
<div class="my-carousel-info">
<h3 class="my-carousel-title">サンプル商品5</h3>
<p class="my-carousel-spec">
1個~注文OK<br>
フルカラー印刷
</p>
<p class="my-carousel-price">
<span class="tax-included">@</span>1500円
<span class="tax-included">(税込)</span>
</p>
<a href="#" class="my-carousel-button">詳細を見る</a>
</div>
</div>
</div>
</div>
<!-- /#carousel -->
<!-- 右ボタン -->
<button class="carousel-arrow next">→</button>
</div>
<!-- /.carousel-container -->
<!-- もし全商品の一覧ページなどに飛ばしたい場合 -->
<div class="my-carousel-footer">
<a href="#" class="view-all-button">一覧を見る</a>
</div>
</div>
</section>
<script>
document.addEventListener('DOMContentLoaded', function() {
const carousel = document.getElementById('carousel');
if (!carousel) return;
// ▼ (A) 最初だけスムーズスクロールOFFにして初期位置調整時のガタつきを防ぐ
carousel.classList.add('no-scroll-transition');
// ▼ (1) 元々のアイテムを取得し、クローンで合計3セット分に増やす
const originalItems = Array.from(carousel.children);
const itemCount = originalItems.length;
for (let i = 0; i < 2; i++) {
originalItems.forEach(item => {
const clone = item.cloneNode(true);
carousel.appendChild(clone);
});
}
// ▼ (2) 1カードあたりの幅(カード+gap)を算出
const itemWidth = originalItems[0].getBoundingClientRect().width + 30;
// ▼ (3) 初期位置を「真ん中のセット」になるように調整
const startPos = itemCount * itemWidth;
carousel.scrollLeft = startPos;
// ▼ (4) 1フレーム後にスムーズスクロールを元に戻す
requestAnimationFrame(() => {
carousel.classList.remove('no-scroll-transition');
});
// ▼ (5) 無限ループ処理(端に来たら反対側へ飛ばす)
function onScroll() {
const currentScroll = carousel.scrollLeft;
const maxScrollLeft = itemWidth * (itemCount * 2); // 2周分
// 左端近くまで行ったら右端付近へジャンプ
if (currentScroll < itemWidth) {
carousel.classList.add('no-scroll-transition');
carousel.scrollLeft = currentScroll + itemWidth * itemCount;
carousel.classList.remove('no-scroll-transition');
}
// 右端近くまで行ったら左端付近へジャンプ
else if (currentScroll > maxScrollLeft) {
carousel.classList.add('no-scroll-transition');
carousel.scrollLeft = currentScroll - itemWidth * itemCount;
carousel.classList.remove('no-scroll-transition');
}
}
carousel.addEventListener('scroll', onScroll);
// ▼ (6) ドラッグ操作(PCマウス用)
let isDown = false;
let startX = 0;
let scrollLeftVal = 0;
carousel.addEventListener('mousedown', e => {
isDown = true;
startX = e.pageX - carousel.offsetLeft;
scrollLeftVal = carousel.scrollLeft;
e.preventDefault();
carousel.style.cursor = 'grabbing';
});
carousel.addEventListener('mouseleave', () => {
isDown = false;
carousel.style.cursor = 'grab';
});
carousel.addEventListener('mouseup', () => {
isDown = false;
carousel.style.cursor = 'grab';
});
carousel.addEventListener('mousemove', e => {
if (!isDown) return;
e.preventDefault();
const x = e.pageX - carousel.offsetLeft;
const walk = (x - startX);
// ドラッグ時の移動量を0.3倍で調整してスムーズに
carousel.scrollLeft = scrollLeftVal - walk * 0.3;
});
// ▼ (7) 左右ボタンスクロール
const prevBtn = document.querySelector('.carousel-arrow.prev');
const nextBtn = document.querySelector('.carousel-arrow.next');
const scrollAmount = 280; // 一回の移動量(お好みで)
prevBtn.addEventListener('click', () => {
carousel.scrollBy({ left: -scrollAmount });
});
nextBtn.addEventListener('click', () => {
carousel.scrollBy({ left: scrollAmount });
});
});
</script>
</body>
</html>
Shopifyのテーマエディタから作る方法
Shopifyの管理画面から「オンラインストア」→「テーマ」→「・・・」をクリックし、テーマの「コード編集」を開く
※コード編集は自己責任でお願いいたします。

以下のコードを、そのまま「sections
フォルダ」にある .liquid
ファイル(例:infinite-carousel.liquid
)として保存してください。ShopifyのOnline Store 2.0対応テーマの場合は、このセクションをテーマエディタから追加できます。
下記コードを張り付けてご使用ください。
下記箇所を変更してご利用ください。
①タイトル
<h2 class=”my-carousel-heading”> サンプル商品が並ぶカルーセル</h2>
②商品画像・商品名
<img src=”https://via.placeholder.com/300?text=Product+1″ alt=”サンプル商品1″>
③商品リンク
<a href=”#” class=”my-carousel-button”>詳細を見る</a>(#をリンク先に設定してください。)
④商品説明
<p class=”my-carousel-spec”>1個~注文OK<br></p>
⑤詳細ボタンの色
.my-carousel-button {background-color: #ff5722;}
⑥一覧ボタンの色
.view-all-button {background-color: #ff5722;}


{% comment %}
==============================
Infinite Carousel Section
==============================
{% endcomment %}
<section class="my-carousel-section">
<style>
/****************************************
* (1) 全体スタイル
****************************************/
.my-carousel-section {
position: relative;
width: 100vw; /* 幅をブラウザに合わせる */
left: 50%;
transform: translateX(-50%);
background-color: #e0e0e0;
padding: 60px 0;
box-sizing: border-box;
}
.my-carousel-wrapper {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
box-sizing: border-box;
}
.my-carousel-heading {
max-width: 700px;
margin: 0 auto;
font-weight: bold;
text-align: center;
font-size: 24px;
padding: 20px;
position: relative;
border-radius: 5px;
color: #515151;
margin-bottom: 30px;
}
/****************************************
* (2) カルーセル部分
****************************************/
.carousel-container {
position: relative;
margin: 0 auto;
overflow: hidden; /* スクロール領域外を隠す */
}
/* スムーズスクロール。ただし最初とジャンプ時だけOFFにするためのクラスと併用 */
.my-carousel-grid {
display: flex;
flex-wrap: nowrap;
gap: 30px;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
user-select: none;
cursor: grab;
scrollbar-width: none; /* Firefoxでスクロールバー非表示 */
-ms-overflow-style: none; /* IE/Edgeで非表示 */
scroll-behavior: smooth; /* スムーズスクロール */
box-sizing: border-box;
padding-bottom: 10px;
}
.my-carousel-grid::-webkit-scrollbar {
display: none; /* Chrome, Safari 等のスクロールバー非表示 */
}
.my-carousel-grid:active {
cursor: grabbing;
}
/* ジャンプ時だけスムーズスクロールをOFFにするためのクラス */
.no-scroll-transition {
scroll-behavior: auto !important;
}
/****************************************
* (3) カードデザイン
****************************************/
.my-carousel-item {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
transition: transform 0.3s ease, box-shadow 0.3s ease;
color: #333;
display: flex;
flex-direction: column;
align-items: center;
flex: 0 0 280px; /* 横幅(お好みで調整) */
margin-bottom: 0;
}
.my-carousel-item:hover {
transform: translateY(-3px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
.my-carousel-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
padding: 20px;
}
.my-carousel-image {
width: 250px;
height: 250px;
border-radius: 4px;
overflow: hidden;
flex-shrink: 0;
}
.my-carousel-image img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.my-carousel-info {
width: 100%;
text-align: center;
}
.my-carousel-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 6px;
color: #333;
}
.my-carousel-spec {
font-size: 14px;
color: #666;
margin-bottom: 6px;
line-height: 1.4;
font-weight: bold;
}
.my-carousel-price {
font-size: 22px;
font-weight: bold;
color: #ff5722;
}
.my-carousel-price .tax-included {
font-size: 0.6em;
vertical-align: baseline;
}
.my-carousel-button {
display: inline-block;
margin-top: 10px;
font-size: 14px;
font-weight: bold;
color: #fff !important;
background-color: #ff5722;
padding: 8px 16px;
border-radius: 4px;
text-decoration: none;
border: none;
cursor: pointer;
transition: opacity 0.2s ease;
}
.my-carousel-button:hover {
opacity: 0.9;
}
/****************************************
* (4) 左右矢印ボタン
****************************************/
.carousel-arrow {
position: absolute;
top: 50%;
z-index: 5;
transform: translateY(-50%);
background: rgba(0, 0, 0, 0.5);
color: #fff;
border: none;
width: 40px;
height: 40px;
cursor: pointer;
border-radius: 50%;
font-size: 20px;
}
.carousel-arrow.prev {
left: 10px;
}
.carousel-arrow.next {
right: 10px;
}
/****************************************
* (5) 下部ボタン部分
****************************************/
.my-carousel-footer {
margin-top: 40px;
text-align: center;
line-height: 1.8;
font-size: 16px;
max-width: 800px;
margin-left: auto;
margin-right: auto;
}
.view-all-button {
display: inline-block;
background-color: #ff5722;
color: #fff !important;
font-size: 18px;
font-weight: bold;
padding: 12px 40px;
border-radius: 6px;
text-decoration: none;
margin-top: 20px;
transition: transform 0.1s ease-in-out, background-color 0.3s;
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
}
.view-all-button:hover {
background-color: #e64a19;
}
.view-all-button:active {
transform: scale(0.9);
box-shadow: inset 0 4px 6px rgba(0,0,0,0.2);
}
</style>
<div class="my-carousel-wrapper">
<h2 class="my-carousel-heading">
サンプル商品が並ぶカルーセル!
</h2>
<!-- カルーセル全体のラッパ -->
<div class="carousel-container">
<!-- 左ボタン -->
<button class="carousel-arrow prev">←</button>
<!-- スライド領域 -->
<!-- 初期ロード時は「no-scroll-transition」を付与してガタつき防止 -->
<div class="my-carousel-grid no-scroll-transition" id="carousel">
<!-- 以下、サンプル商品カードを複数(5個) -->
<div class="my-carousel-item">
<div class="my-carousel-content">
<div class="my-carousel-image">
<img src="https://via.placeholder.com/300?text=Product+1" alt="サンプル商品1">
</div>
<div class="my-carousel-info">
<h3 class="my-carousel-title">サンプル商品1</h3>
<p class="my-carousel-spec">
1個~注文OK<br>
フルカラー印刷
</p>
<p class="my-carousel-price">
<span class="tax-included">@</span>500円
<span class="tax-included">(税込)</span>
</p>
<a href="#" class="my-carousel-button">詳細を見る</a>
</div>
</div>
</div>
<div class="my-carousel-item">
<div class="my-carousel-content">
<div class="my-carousel-image">
<img src="https://via.placeholder.com/300?text=Product+2" alt="サンプル商品2">
</div>
<div class="my-carousel-info">
<h3 class="my-carousel-title">サンプル商品2</h3>
<p class="my-carousel-spec">
1個~注文OK<br>
フルカラー印刷
</p>
<p class="my-carousel-price">
<span class="tax-included">@</span>700円
<span class="tax-included">(税込)</span>
</p>
<a href="#" class="my-carousel-button">詳細を見る</a>
</div>
</div>
</div>
<div class="my-carousel-item">
<div class="my-carousel-content">
<div class="my-carousel-image">
<img src="https://via.placeholder.com/300?text=Product+3" alt="サンプル商品3">
</div>
<div class="my-carousel-info">
<h3 class="my-carousel-title">サンプル商品3</h3>
<p class="my-carousel-spec">
1個~注文OK<br>
フルカラー印刷
</p>
<p class="my-carousel-price">
<span class="tax-included">@</span>900円
<span class="tax-included">(税込)</span>
</p>
<a href="#" class="my-carousel-button">詳細を見る</a>
</div>
</div>
</div>
<div class="my-carousel-item">
<div class="my-carousel-content">
<div class="my-carousel-image">
<img src="https://via.placeholder.com/300?text=Product+4" alt="サンプル商品4">
</div>
<div class="my-carousel-info">
<h3 class="my-carousel-title">サンプル商品4</h3>
<p class="my-carousel-spec">
1個~注文OK<br>
フルカラー印刷
</p>
<p class="my-carousel-price">
<span class="tax-included">@</span>1200円
<span class="tax-included">(税込)</span>
</p>
<a href="#" class="my-carousel-button">詳細を見る</a>
</div>
</div>
</div>
<div class="my-carousel-item">
<div class="my-carousel-content">
<div class="my-carousel-image">
<img src="https://via.placeholder.com/300?text=Product+5" alt="サンプル商品5">
</div>
<div class="my-carousel-info">
<h3 class="my-carousel-title">サンプル商品5</h3>
<p class="my-carousel-spec">
1個~注文OK<br>
フルカラー印刷
</p>
<p class="my-carousel-price">
<span class="tax-included">@</span>1500円
<span class="tax-included">(税込)</span>
</p>
<a href="#" class="my-carousel-button">詳細を見る</a>
</div>
</div>
</div>
</div>
<!-- /#carousel -->
<!-- 右ボタン -->
<button class="carousel-arrow next">→</button>
</div>
<!-- /.carousel-container -->
<!-- 下部ボタン例 -->
<div class="my-carousel-footer">
<a href="#" class="view-all-button">一覧を見る</a>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const carousel = document.getElementById('carousel');
if (!carousel) return;
// ▼ (A) 初期アニメーションOFF: ガタつき防止
carousel.classList.add('no-scroll-transition');
// ▼ (1) 元々のアイテムを取得し、クローンで合計3セット分に増やす
const originalItems = Array.from(carousel.children);
const itemCount = originalItems.length;
for (let i = 0; i < 2; i++) {
originalItems.forEach(item => {
const clone = item.cloneNode(true);
carousel.appendChild(clone);
});
}
// ▼ (2) 1カードあたりの幅(カード+gap)
const itemWidth = originalItems[0].getBoundingClientRect().width + 30;
// ▼ (3) 初期位置 = 真ん中のセット
const startPos = itemCount * itemWidth;
carousel.scrollLeft = startPos;
// ▼ (4) 1フレーム後にスムーズスクロールONに戻す
requestAnimationFrame(() => {
carousel.classList.remove('no-scroll-transition');
});
// ▼ (5) 無限ループ処理 (端で反対側へジャンプ)
function onScroll() {
const currentScroll = carousel.scrollLeft;
const maxScrollLeft = itemWidth * (itemCount * 2); // 2周分
// 左端近く → 右端付近へ
if (currentScroll < itemWidth) {
carousel.classList.add('no-scroll-transition');
carousel.scrollLeft = currentScroll + itemWidth * itemCount;
carousel.classList.remove('no-scroll-transition');
}
// 右端近く → 左端付近へ
else if (currentScroll > maxScrollLeft) {
carousel.classList.add('no-scroll-transition');
carousel.scrollLeft = currentScroll - itemWidth * itemCount;
carousel.classList.remove('no-scroll-transition');
}
}
carousel.addEventListener('scroll', onScroll);
// ▼ (6) ドラッグ操作(PCマウス用)
let isDown = false;
let startX = 0;
let scrollLeftVal = 0;
carousel.addEventListener('mousedown', e => {
isDown = true;
startX = e.pageX - carousel.offsetLeft;
scrollLeftVal = carousel.scrollLeft;
e.preventDefault();
carousel.style.cursor = 'grabbing';
});
carousel.addEventListener('mouseleave', () => {
isDown = false;
carousel.style.cursor = 'grab';
});
carousel.addEventListener('mouseup', () => {
isDown = false;
carousel.style.cursor = 'grab';
});
carousel.addEventListener('mousemove', e => {
if (!isDown) return;
e.preventDefault();
const x = e.pageX - carousel.offsetLeft;
const walk = (x - startX);
// ドラッグ移動量を0.3倍に
carousel.scrollLeft = scrollLeftVal - walk * 0.3;
});
// ▼ (7) 左右ボタンスクロール
const prevBtn = document.querySelector('.carousel-arrow.prev');
const nextBtn = document.querySelector('.carousel-arrow.next');
const scrollAmount = 280; // 一回の移動量(お好みで)
prevBtn.addEventListener('click', () => {
carousel.scrollBy({ left: -scrollAmount });
});
nextBtn.addEventListener('click', () => {
carousel.scrollBy({ left: scrollAmount });
});
});
</script>
</section>
{% schema %}
{
"name": "Infinite Carousel",
"settings": [],
"blocks": [],
"presets": [
{
"name": "Infinite Carousel"
}
]
}
{% endschema %}
テーマエディタに移動して、セクションを追加を押すと先ほど作成したinfinite-carouse
が表示されます。

コードを導入する際の重要な注意点
1. 商品画像サイズを統一する
商品画像を表示する際には、画像サイズを統一することが大切です。推奨サイズは300×300pxですが、必要に応じて適切なサイズを設定しましょう。サイズが異なる画像が混在すると、カルーセルのデザインが崩れる可能性があります。
2. レスポンシブデザインへの対応
本コードはレスポンシブ設計となっていますが、使用する画像数やカルーセルの幅によって細かな調整が必要な場合があります。モバイル端末でもきれいに表示されるよう、必ずスマートフォンやタブレットでも動作確認を行ってください。
3. JavaScript動作の確認とトラブルシューティング
ShopifyのテーマによってはJavaScriptが他のコードと競合し、カルーセルがうまく動作しないことがあります。その場合はブラウザの開発者ツール(コンソール)でエラーがないか確認し、問題を特定しましょう。また、他のアプリやカスタムコードとの衝突も確認が必要です。
追加のカスタマイズ方法
矢印ボタンのデザインや位置調整
左右に表示される矢印ボタンの位置やサイズ、色などはCSSの「.carousel-arrow」クラスを編集することで自由に変更可能です。ブランドやサイトのイメージに合ったデザインに調整しましょう。
カルーセルのスクロール速度・移動量調整
JavaScriptコードの「scrollAmount」という変数を編集すると、スクロール時の移動量を調整できます。商品カードのサイズや個数に合わせてユーザーが快適に操作できるよう調整してください。
商品カードのデザインカスタマイズ
商品カードの背景色、テキストフォント、余白など細かなデザイン変更はCSSの「.my-carousel-item」「.my-carousel-title」「.my-carousel-price」などを調整することで簡単に実現できます。独自性の高いデザインに仕上げ、ブランドの個性を演出しましょう。
まとめ
Shopifyで商品カルーセルを効果的に活用することで、ユーザーエクスペリエンスの向上と売上増加が期待できます。本記事で解説した導入手順や注意点、カスタマイズ方法を参考に、自社サイトに最適なカルーセルを構築してみてください。導入後は定期的にユーザーの反応を分析し、さらなる改善を続けましょう。
コメント