【JavaScript】ライブラリを使わない!シンプルな「スライダー」の作り方!【カルーセル】

しゅーた(@chibasyuta)です!
この記事では「スライダー」の作り方を解説します!「カルーセル」とも呼ばれるやつですね。
「スライダー」の作り方には様々なものがり、「Swiper」や「jQuery」などのライブラリを使う方法もありますが、この記事で扱うのは、そういった類のものは使わず、そのままの「JavaScript」で実装する、というものになります。
「JavaScript」の理解に繋がるだろうし、「JavaScript」だけで作った方がカスタマイズ性に優れていたりします。
実務では「Swiper」を使う場合も多いと思いますが、「JavaScript」だけによる「スライダー」の実装方法を知っておくと「Swiper」の使い方のさらなる理解に繋がるとも思うので、ぜひ挑戦してみてください!
この記事の内容!
- 「スライダー」とは何か?
- 「スライダー」の作り方!
- 自動再生機能の追加方法
- 「プログレスバー」の追加方法!

動画の方が細かいステップに分けて解説していますし、細かい解説も多くつけ加えているので、分かりやすさという点では動画の方がおすすめです!もう既に作った経験がある方や基本来なロジックが分かる方は、ブログ記事版の方が素早く作れると思います!
それでは、内容へ入ります!
「スライダー」とは何か?
Web制作における「スライダー」や「カルーセル」とは、複数のコンテンツ(画像やテキストなど)を一定の間隔で切り替えながら表示するインターフェースのことを指します。
これらはWebサイトのデザインでよく使われる手段で、限られたスペースにコンテンツを収めたい場合に活用できます。
また、動きのコンテンツはユーザーの目につくので、コンテンツを目立たせることができます。
とにかく、それが「スライダー」や「カルーセル」です。以後この記事では「スライダー」と統一して呼ぶことにします。
「スライダー」の作り方!


まずは基本的な実装から始めて、段階的に機能を追加していこうと思います。
皆さんも順番に作り上げてもらった方が、作りやすいと思いますね。いろんな実装に慣れている方は、好きな方法で進めてください!
基本的なスライダーの作り方!
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="carousel">
<div class="container">
<ul>
<li><img src="./img/portfolio1_new.jpg"></li>
<li><img src="./img/portfolio2_new.jpg"></li>
<li><img src="./img/portfolio3_new.jpg"></li>
<li><img src="./img/portfolio4_new.jpg"></li>
</ul>
</div>
<div class="button-box">
<button id="prev"><</button>
<button id="next">></button>
</div>
</div>
<script src="test.js"></script>
</body>
</html>
@charset "utf-8";
html {
font-size: 16px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.carousel {
overflow: hidden;
width: 500px;
height: 450px;
margin: 64px auto;
position: relative;
}
.container {
height: 350px;
font-size: 40px;
overflow: hidden;
margin-bottom: 20px;
}
ul {
display: flex;
list-style: none;
height: 100%;
transition-duration: .6s;
}
li {
width: 100%;
height: 100%;
min-width: 100%;
}
img {
width: 100%;
height: 100%;
object-fit: cover;
}
.button-box {
text-align: right;
}
button {
border: none;
padding: 8px 16px;
font-size: 30px;
cursor: pointer;;
}
button:hover {
background-color: black;
color: white;
}
"use strict";
const ul = document.querySelector('ul');
const slides = ul.children;
const prev = document.getElementById('prev');
const next = document.getElementById('next');
let currentIndex = 0;
prev.addEventListener('click', () => {
currentIndex--;
currentIndex = currentIndex % slides.length;
moveSlide();
});
next.addEventListener('click', () => {
currentIndex++;
currentIndex = currentIndex % slides.length;
moveSlide();
});
function moveSlide() {
if ( currentIndex < 0 ) {
currentIndex = slides.length - 1;
}
const slideWidth = slides[0].getBoundingClientRect().width;
ul.style.transform = `translateX(${-1 * slideWidth * currentIndex}px)`;
}
ここでは「JavaScript」の解説だけをします。
「currentIndex」という変数で「今表示している画像はどれなのか」を管理します。
「ul」を動かすことで、今表示されている画像を変更するというもので、その部分の基本的なロジックは下記です。
const slideWidth = slides[0].getBoundingClientRect().width;
ul.style.transform = `translateX(${-1 * slideWidth * currentIndex}px)`;
この部分でスライドの幅を取得して、何枚分のスライドを動かすのか、というのを「currentIndex」と連携することで実現しています。
currentIndex = currentIndex % slides.length;
また「currentIndex 」をこのように少しいじることで、常にどれかのスライドが表示されるようにしています。スライドの枚数を超えてcurrentIndex が増えそうになったら、最初のスライドに戻るような仕組みを「%」という剰余演算子で作っています。
if ( currentIndex < 0 ) {
currentIndex = slides.length - 1;
}
「currentIndex」がマイナスになることを防ぐためには、このif文を用いています。
ナビゲーションのためのボタンを追加!
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="carousel">
<div class="container">
<ul>
<li><img src="./img/portfolio1_new.jpg"></li>
<li><img src="./img/portfolio2_new.jpg"></li>
<li><img src="./img/portfolio3_new.jpg"></li>
<li><img src="./img/portfolio4_new.jpg"></li>
</ul>
</div>
<div class="button-box">
<button id="prev"><</button>
<button id="next">></button>
</div>
<div class="nav"></div>
</div>
<script src="test.js"></script>
</body>
</html>
@charset "utf-8";
html {
font-size: 16px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.carousel {
overflow: hidden;
width: 500px;
height: 450px;
margin: 64px auto;
position: relative;
}
.container {
height: 350px;
font-size: 40px;
overflow: hidden;
margin-bottom: 20px;
}
ul {
display: flex;
list-style: none;
height: 100%;
transition-duration: .6s;
}
li {
width: 100%;
height: 100%;
min-width: 100%;
}
img {
width: 100%;
height: 100%;
object-fit: cover;
}
.button-box {
text-align: right;
}
button {
border: none;
padding: 8px 16px;
font-size: 30px;
cursor: pointer;;
}
button:hover {
background-color: black;
color: white;
}
.nav {
position: absolute;
bottom: 0;
left: 0;
right: 0;
text-align: center;
}
.nav button {
width: 40px;
height: 40px;
background-color: #ddd;
border-radius: 50%;
}
.nav button + button {
margin-left: 8px;
}
.nav button.current {
background-color: black;
}
"use strict";
const ul = document.querySelector('ul');
const slides = ul.children;
const prev = document.getElementById('prev');
const next = document.getElementById('next');
const nav = document.querySelector('.nav');
const navButton = [];
let currentIndex = 0;
createNavButtons();
prev.addEventListener('click', () => {
currentIndex--;
currentIndex = currentIndex % slides.length;
moveSlide();
updateNavBtn()
});
next.addEventListener('click', () => {
currentIndex++;
currentIndex = currentIndex % slides.length;
moveSlide();
updateNavBtn()
});
function moveSlide() {
if ( currentIndex < 0 ) {
currentIndex = slides.length - 1;
}
const slideWidth = slides[0].getBoundingClientRect().width;
ul.style.transform = `translateX(${-1 * slideWidth * currentIndex}px)`;
}
function createNavButtons() {
for (let i = 0; i < slides.length; i++) {
const button = document.createElement('button');
if ( i === currentIndex ) {
button.classList.add('current');
}
navButton.push(button);
button.addEventListener('click', () => {
currentIndex = i;
moveSlide();
navButton.forEach( btn => {
btn.classList.remove('current');
} );
navButton[currentIndex].classList.add('current');
});
nav.appendChild(button);
}
}
function updateNavBtn() {
navButton.forEach( btn => {
btn.classList.remove('current');
} );
navButton[currentIndex].classList.add('current');
}
まずHTMLファイルに「nav」というクラス属性を持った要素を追加します。
そして、「createNavButtons()」という関数を作り、そこでボタンを作り追加するという実装にしました。これは画像の数が今後増えても対応できるようにするためです。
const navButton = [];
配列に参照情報を持たせておくことで、そこから扱うことができるので便利です。
クリックしたボタンに応じて「currentIndex」を更新したあと、「moveSlide()」を実行できるようにします。
「#prev」と「#next」のボタンを押した時に、ナビゲーションのボタンのスタイルも変更されるように「updateNavBtn()」という関数を作り、実行できるようにします。
時間経過で自動的に次のスライドに移動させる!
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="carousel">
<div class="container">
<ul>
<li><img src="./img/portfolio1_new.jpg"></li>
<li><img src="./img/portfolio2_new.jpg"></li>
<li><img src="./img/portfolio3_new.jpg"></li>
<li><img src="./img/portfolio4_new.jpg"></li>
</ul>
</div>
<div class="button-box">
<button id="prev"><</button>
<button id="next">></button>
</div>
<div class="text"></div>
<div class="nav"></div>
<div class="progress-bar">
<div class="progress"></div>
</div>
</div>
<script src="js.js"></script>
</body>
</html>
.progress-bar {
width: 100px;
height: 20px;
background-color: #ddd;
position: absolute;
bottom: 50px;
}
.progress {
width: 0;
height: 100%;
background-color: black;
}
.progress.go {
width: 100%;
transition-duration: 2s;
transition-timing-function: linear;
}
これらのCSSファイルを追加
"use strict";
const ul = document.querySelector('ul');
const prev = document.getElementById('prev');
const next = document.getElementById('next');
const slides = ul.children;
const nav = document.querySelector('.nav');
const navButton = [];
const progress = document.querySelector('.progress');
let currentIndex = 0;
let autoPlayId;
createNavButtons();
prev.addEventListener('click', () => {
currentIndex--;
currentIndex = currentIndex % slides.length;
moveSlide();
updateNavBtn();
clearInterval( autoPlayId );
restartProgress();
autoPlay();
});
next.addEventListener('click', () => {
currentIndex++;
currentIndex = currentIndex % slides.length;
moveSlide();
updateNavBtn();
clearInterval( autoPlayId );
restartProgress();
autoPlay();
});
function moveSlide() {
if ( currentIndex < 0 ) {
currentIndex = slides.length - 1;
}
const slideWidth = slides[0].getBoundingClientRect().width;
ul.style.transform = `translateX(${-1 * slideWidth * currentIndex}px)`;
document.querySelector('.text').textContent = (currentIndex);
}
function createNavButtons() {
for (let i = 0; i < slides.length; i++) {
const button = document.createElement('button');
if ( i === currentIndex ) {
button.classList.add('current');
}
navButton.push(button);
button.addEventListener('click', () => {
currentIndex = i;
moveSlide();
navButton.forEach( btn => {
btn.classList.remove('current');
} );
navButton[currentIndex].classList.add('current');
clearInterval( autoPlayId );
restartProgress();
autoPlay();
});
nav.appendChild(button);
}
}
function updateNavBtn() {
navButton.forEach( btn => {
btn.classList.remove('current');
} );
navButton[currentIndex].classList.add('current');
restartProgress();
}
autoPlay();
restartProgress();
function autoPlay() {
autoPlayId =
setInterval(() => {
currentIndex++;
currentIndex = currentIndex % slides.length;
moveSlide();
updateNavBtn();
restartProgress();
}, 2000);
}
function restartProgress() {
progress.classList.remove('go');
setTimeout(() => {
progress.classList.add('go');
}, 100);
}
「autoPlay()」と「restartProgress()」を作り、それぞれ必要なタイミングで呼び出します。
ボタンのクリックなどで画像を手動で切り替えた場合、「clearInterval( autoPlayId );」のようにして、自動的に次のスライドに切り替わるのをキャンセルし、また再び新しいタイマーを起動させる、というような実装です。
関連リンク!
これらの記事もおすすめです。
【JavaScript】「アコーディオンメニュー」をライブラリなしで作る方法【アニメーションつき】
【JavaScript】「ライブラリーを使わずに「ハンバーガーメニュー」を作る方法!【分かりやすい】
【JavaScript】ライブラリを使わない「タブメニュー」の作り方!【シンプル】
【JavaScript】モーダルウィンドウの作り方!【分かりやすい】
おすすめの再生リスト!
こちらは僕が制作したYouTubeの再生リスト「JavaScriptの入門編」です。
「JavaScriptの入門編」はWeb制作を勉強している方がJavaScriptに入門する際に知っておきたい情報をまとめたコンテンツとなります。
こちらの再生リストで「JavaScript」について「丁寧」に解説しているので、もし気になる方はチェックしてみてください!一緒に楽しく学習しましょう!!
まとめ!
今回は段階的にスライダーの作り方の解説をしました!
もっと細かい解説が必要な場合は、僕のYouTubeの動画をご視聴ください!また、質問などがありましたらコメントをお気軽にどうぞ!

それではまた!
あ、あと因みに、この前チャンネル登録者数1,000人達成できました!っていうね!ありがとう!