《Javascript》横並びにした画像を無限に横スクロールさせる
公開日:2025年10月16日 最終更新日:2025年10月16日
横並びに配置した画像をスライドショーのように無限に横スクロールさせる方法を紹介します。
JavaScriptでスクロールスピードとスクロール方向を設定しています。
1つのスライダーだけスクロール
DEMO
HTML
<div class="marqueer">
<ul>
<li><img src="https://blog.grinee.net/demo/images/image1.png" alt=""></li>
<li><img src="https://blog.grinee.net/demo/images/image2.png" alt=""></li>
<li><img src="https://blog.grinee.net/demo/images/image3.png" alt=""></li>
</ul>
</div>
CSS
並べたい写真の枚数や余白はこちらで調整します。
.marqueer {
margin: 10px 0;
overflow: hidden;
}
.marqueer ul {
display: flex;
margin: 0;
padding: 0;
width: max-content;
}
.marqueer ul li {
list-style: none;
padding: 0 5px; /* 余白 */
width: calc(100vw / 3 - 10px); /* 3 写真の枚数にあわせる */
}
.marqueer img {
display: block;
width: 100%;
}
JavaScript
スクロールスピードとスクロール方向を設定しています。
window.addEventListener('load', function () {
const marquee = document.querySelector('.marqueer ul'); // ul要素
const items = Array.from(marquee.children); // 子要素
const speedSeconds = 20; // スクロール1回にかかる秒数
const direction = 'left'; // 'left' または 'right'
// 無限スクロール用に複製
items.forEach(item => marquee.appendChild(item.cloneNode(true)));
let marqueeWidth = marquee.scrollWidth / 2;
let pos = direction === 'left' ? 0 : -marqueeWidth;
const pixelsPerFrame = marqueeWidth / (speedSeconds * 60);
function animate() {
pos += direction === 'left' ? -pixelsPerFrame : pixelsPerFrame;
// 無限ループ
if (pos <= -marqueeWidth) pos += marqueeWidth;
if (pos >= 0) pos -= marqueeWidth;
marquee.style.transform = `translateX(${pos}px)`;
requestAnimationFrame(animate);
}
animate();
});
複数のスライダーを設置する
左右交互にスライダーをスクロールさせています。
DEMO
HTML
<div class="marqueer2">
<ul>
<li><img src="https://blog.grinee.net/demo/images/image1.png" alt=""></li>
<li><img src="https://blog.grinee.net/demo/images/image2.png" alt=""></li>
<li><img src="https://blog.grinee.net/demo/images/image3.png" alt=""></li>
</ul>
</div>
<div class="marqueer2">
<ul>
<li><img src="https://blog.grinee.net/demo/images/image1.png" alt=""></li>
<li><img src="https://blog.grinee.net/demo/images/image2.png" alt=""></li>
<li><img src="https://blog.grinee.net/demo/images/image3.png" alt=""></li>
</ul>
</div>
<div class="marqueer2">
<ul>
<li><img src="https://blog.grinee.net/demo/images/image1.png" alt=""></li>
<li><img src="https://blog.grinee.net/demo/images/image2.png" alt=""></li>
<li><img src="https://blog.grinee.net/demo/images/image3.png" alt=""></li>
</ul>
</div>
CSS
1つだけの時と同じです。
.marqueer2 {
margin: 10px 0;
overflow: hidden;
}
.marqueer2 ul {
display: flex;
margin: 0;
padding: 0;
width: max-content;
}
.marqueer2 ul li {
list-style: none;
padding: 0 5px; /* 余白 */
width: calc(100vw / 3 - 10px); /* 3 写真の枚数にあわせる */
}
.marqueer2 img {
display: block;
width: 100%;
}
JavaScript
左右の流れる順番を変える場合はconst directionの’left’ : ‘right’; を入れ替えてください。
window.addEventListener('load', function () {
const marquees = document.querySelectorAll('.marqueer2');
marquees.forEach((marqueeWrapper, index) => {
const marquee = marqueeWrapper.querySelector('ul'); // ul要素
const items = Array.from(marquee.children); // 子要素
const speedSeconds = 20; // スクロール1回にかかる秒数
const direction = (index % 2 === 0) ? 'left' : 'right'; // 奇数番目は左、偶数は右
// 無限スクロール用に複製
items.forEach(item => marquee.appendChild(item.cloneNode(true)));
const marqueeWidth = marquee.scrollWidth / 2;
let pos = direction === 'left' ? 0 : -marqueeWidth;
const pixelsPerFrame = marqueeWidth / (speedSeconds * 60);
function animate() {
pos += direction === 'left' ? -pixelsPerFrame : pixelsPerFrame;
// 無限ループ
if (pos <= -marqueeWidth) pos += marqueeWidth;
if (pos >= 0) pos -= marqueeWidth;
marquee.style.transform = `translateX(${pos}px)`;
requestAnimationFrame(animate);
}
animate();
});
});