JavaScript02 自作スライドショーで動きの基礎を段階的に学ぶ(入門編)

JavaScriptを使った動きのあるWebサイトは、より魅力的で印象に残るものです。ここでは、初心者の方を対象に、Web制作で役立つ『スライドショー』をゼロから自作してみます。
最初はシンプルな構造から始め、フェードするスライドショーから、横に移動するスライドショーへの変更などをJavaScriptのみで行います。記事が長くなったので、このあとは応用編で、さらにブラッシュアップしたインジケーターの追加やレスポンシブ対応を行なっています。プログラミング初心者の方でも一歩一歩進められる内容となっていますので、一緒にスライドショー制作の楽しさを体感してみましょう!
JSを使わないCSSだけの基本的なスライドショー
まずは、HTMLとCSSだけで、画像を自動で切り替えるスライドショーを作成します。CSSもアニメーション用のプロパティを導入するだけで、JavaScriptを使わなくても十分にスライドさせることが可能です。ここでは、固定幅の800px*400pxの画像幅のスライダーです。
See the Pen CSSだけで作成するスライダー by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.
HTMLの解説
<div class="slideshow"> <div class="slides"> <img src="https://placehold.jp/410042/ffffff/800x400.jpg?text=slide01" alt="Slide 1"> <img src="https://placehold.jp/ffcb5c/ffffff/800x400.jpg?text=slide02" alt="Slide 2"> <img src="https://placehold.jp/4991ee/ffffff/800x400.jpg?text=slide03" alt="Slide 3"> </div>
<div class="slideshow">
はスライドショー全体を囲むコンテナ。<div class="slides">
はスライドを横並びに表示するための要素。<img>
はスライドショーの画像要素。今回はダミー画像生成サイト(placehold.jp)より作成しています。
CSSの解説
.slideshow { width: 800px; height: 400px; overflow: hidden; position: relative; } .slides { display: flex; width: 100%; height: 100%; animation: slide 9s infinite; } .slides img { width: 800px; height: 400px; flex-shrink: 0; object-fit: cover; } @keyframes slide { 0% { transform: translateX(0); } 33.33% { transform: translateX(-800px); } 66.66% { transform: translateX(-1600px); } 100% { transform: translateX(0); } }
.slideshow
- スライドショー全体を囲む部分です。
- 横幅800px、高さ400pxの枠を作り、画像がその中に収まるようにしています。
overflow: hidden;
を使って、枠からはみ出した画像部分は見えなくしています。
.slides
- 複数の画像を横一列に並べています。
display: flex;
を使います。 - 後でアニメーションで画像が左右に動くようにするため、幅や高さをスライドショーと同じに設定
- 複数の画像を横一列に並べています。
.slides img
- スライドショーの画像そのものです。
- 画像サイズをスライドショー枠のサイズ(800px × 400px)に合わせるため、
width
とheight
を設定しています。 - 画像が縦横比を崩さず収まるように、
object-fit: cover;
を指定。
@keyframes slide
- スライドショーの画像を自動で切り替えるための「動き」を定義する部分です。
@keyframes
はCSSでアニメーションを作るときに使います。動きの始まりから終わりまでを時間の割合で設定します。
- 0%: 最初の画像を表示。
- 33.33%: 次の画像が表示されるように、スライド全体を左に800px移動(
transform: translateX(-800px);
)。 - 66.66%: さらに次の画像が表示されるように、左に1600px移動。
- 100%: 最初の位置(0px)に戻る。
- アニメーションの設定
.slides
に対して、animation: slide 9s infinite;
を設定しています。slide
は上で定義した動きを指します。9s
はアニメーションが1回終わるまでにかかる時間(9秒)。infinite
はアニメーションを無限に繰り返すという指定。
簡単:JavaScriptを使ったスライド(フェードイン)
HTML/CSSスライダーは、CSSアニメーション(@keyframes
)とtransform: translateX
を使って、画像を一定間隔で自動的に切り替えます。画像は横並び(flex
)で配置し、CSSの@keyframes
でアニメーションをループさせて切り替えを実現しました。コードはとても軽量で簡単です。
ただし、切り替え間隔やスピードを動的に変えるや、さまざまなことを追加する場合、JavaScriptを必要になります。
以下のスライドショーは、HTML/CSS/JavaScriptを使ったフェードインするスライドショーの作成です。
See the Pen setIntervalを使ったスライドショー by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.
HTMLの解説
<div class="slideshow"></div>
- スライドショー全体を囲むコンテナ。
- この中に、JavaScriptで生成した画像を動的に追加します。
- 初期状態では空です(画像はJavaScriptで追加されます)←大事
CSSの解説
.slideshow { width: 800px;/* サイズは用意した写真に合わせる */ height: 400px;/* サイズは用意した写真に合わせる */ overflow: hidden; position: relative; } .slideshow img { width: 100%; height: auto; object-fit: cover; position: absolute; top: 0; left: 0; opacity: 0; transition: opacity 1s ease-in-out; /* フェードアニメーション */ } .slideshow img.active { opacity: 1; /* 表示する画像の透明度を変更 */ }
.slideshow
- コンテナの幅と高さを指定。
overflow: hidden;
で、コンテナ外にはみ出した要素を非表示にします。position: relative;
にすることで、内部の画像要素を相対位置で基準を決めます。
.slideshow img
- すべての画像をコンテナの中に重ねて配置(
position: absolute;
)。 - 初期状態では画像の透明度(
opacity
)を0
に設定し、見えない状態にします。 transition
でフェードアニメーションを設定し、opacity
が変更されると滑らかに変化します。
- すべての画像をコンテナの中に重ねて配置(
.slideshow img.active
- 表示する画像に
active
クラスを付与。 opacity: 1
で画像を表示。
- 表示する画像に
JavaScriptの解説
画像データの設定
const images = [ "https://placehold.jp/410042/ffffff/800x400.jpg?text=slide01", "https://placehold.jp/ffcb5c/ffffff/800x400.jpg?text=slide02", "https://placehold.jp/4991ee/ffffff/800x400.jpg?text=slide03" ];
- 配列imagesに画像のURLを格納。
- 本来はHTML/CSS/JSファイルの入ったフォルダにimagesフォルダを作成して格納 images/slide01.jpgとなる
- 動的に画像を生成するため、この配列をループして画像を追加します。
スライドショーの画像を追加
const slideshow = document.querySelector('.slideshow'); images.forEach((src, index) => { const img = document.createElement('img'); // 新しい<img>要素を生成 img.src = src; // 画像のURLを設定 img.alt = `Slide ${index + 1}`; // 代替テキストを設定 if (index === 0) img.classList.add('active'); // 最初の画像に`active`クラスを付与 slideshow.appendChild(img); // スライドショーコンテナに追加 });
- document.querySelector(‘.slideshow’)
- HTML内にある、classの.slideshow要素を取得して、画像を追加する対象とします。
- images.forEach
- 配列内のすべての画像URLをループして処理します。
forEach
は、配列内のすべての要素を順番に取り出し、それぞれに対して指定した処理を実行するためのメソッドです。- src部分に画像が入り、index部分にキーが入ります、 最初のループは、画像ファイル,0となり、次のループは次の画像,1となります。
- img.classList.add(‘active’)
- 最初の画像(インデックス0)のみactiveクラスを付与して表示。
具体的な処理の流れ(トレース)
- 1回目のループ:
src
:"https://placehold.jp/410042/ffffff/800x400.jpg?text=slide01"
index
:0
- 新しい
<img>
要素を作成。 src
属性に画像URLを設定。alt
属性にSlide 1
を設定。index === 0
の条件を満たすため、この画像にactive
クラスを付与。- コンテナ(
<div class="slideshow">
)に追加。
- 2回目のループ:
src
:"https://placehold.jp/ffcb5c/ffffff/800x400.jpg?text=slide02"
index
:1
- 新しい
<img>
要素を作成。 src
属性に画像URLを設定。alt
属性にSlide 2
を設定。index === 0
の条件を満たさないため、active
クラスは付与しない。- コンテナに追加。
- 3回目のループ:
src
:"https://placehold.jp/4991ee/ffffff/800x400.jpg?text=slide03"
index
:2
- 同様の手順で、新しい
<img>
要素を作成し、設定。 - コンテナに追加。
タイマー設定
setInterval(() => changeImage(), 3000);
- 3秒(3000ミリ秒)ごとにchangeImage関数を実行。
- 自動で画像が切り替わるスライドショーを実現。
応用:JavaScriptを使った横スライダーの作成
スライドショーの中でも上記のフェードイン方式の場合は、画像が重なるだけなので、横にスライドする方式のスライドショーより実装が簡単です。
横スライド(トランジションで移動)方式 では、最後の画像から最初の画像へ戻る際に「スライド逆戻り」が発生しやすいので、ダミー画像を用意し、瞬時に位置をリセットすることでループ感を演出 する必要があります。
無限ループする横スライド
「最後のスライドから最初にスムーズに戻る」にはダミー画像が必要!です。
最初と最後にダミー画像を配置し、transition終了時に瞬時にリセット することで、シームレスなループが可能になります。
[ダミー] [画像1] [画像2] [画像3] [ダミー] ↑ ↑ ↑ ↑ ↑ 0 1 2 3 4 (currentIndex)
currentIndex = 0
→ ダミー(3枚目の画像
)を表示
currentIndex = 4
→ ダミー(1枚目の画像
)を表示
スライドの移動が完了したら
0 → 3 に瞬時に変更
4 → 1 に瞬時に変更
これにより無限ループしているように見えます。HTMLで用意する方法もありますが、JavaScriptで画像を配列として用意している場合は、JavaScriptでダミー画像を用意することも可能です。下記のコードはJavaScriptでダミー画像を用意した場合です。
実装:JavaScript 配列を使った横スライダー
See the Pen JavaScript 配列を使った横スライダー by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.
HTMLの解説
スライダーなので、前へ 次へ ボタンも実装してみます。HTMLを下記のように変更します。
<div class="slideshow"> <div class="slides"></div> <button class="prev">前へ</button> <button class="next">次へ</button> </div>
CSSの解説
.slideshow { width: 800px; height: 400px; overflow: hidden; position: relative; border: 2px solid #000; } .slides { display: flex; transition: transform 0.5s ease-in-out; } .slides img { width: 800px; height: 400px; object-fit: cover; } .prev, .next { position: absolute; top: 50%; transform: translateY(-50%); background-color: rgba(0, 0, 0, 0.5); color: white; border: none; padding: 10px 20px; cursor: pointer; font-size: 16px; } .prev { left: 10px; } .next { right: 10px; }
JavaScript全体のコード
// 画像のURLを配列で用意 const images = [ "https://placehold.jp/410042/ffffff/800x400.jpg?text=slide01", "https://placehold.jp/ffcb5c/ffffff/800x400.jpg?text=slide02", "https://placehold.jp/4991ee/ffffff/800x400.jpg?text=slide03" ]; const slidesContainer = document.querySelector('.slides'); // **ダミー画像を含むスライド要素を作成** const createSlideElements = () => { // ダミーとして最後の画像を最初に追加 const firstDummy = document.createElement('img'); firstDummy.src = images[images.length - 1]; // 最後の画像 slidesContainer.appendChild(firstDummy); // 実際の画像を追加 images.forEach(src => { const img = document.createElement('img'); img.src = src; slidesContainer.appendChild(img); }); // ダミーとして最初の画像を最後に追加 const lastDummy = document.createElement('img'); lastDummy.src = images[0]; // 最初の画像 slidesContainer.appendChild(lastDummy); }; // スライドのセットアップ createSlideElements(); const slideImages = document.querySelectorAll('.slides img'); let currentIndex = 1; // **実際のスライド開始位置(1枚目の画像)** const slideWidth = 800; let autoSlide; // **スライドを移動する関数** const moveSlide = (index) => { slidesContainer.style.transition = 'transform 0.5s ease-in-out'; currentIndex = index; slidesContainer.style.transform = `translateX(${-slideWidth * currentIndex}px)`; }; // **transitionend で瞬時にリセットする関数** const resetPosition = () => { if (currentIndex === 0) { // 先頭ダミーに来たら、本当の最後に瞬時に移動 slidesContainer.style.transition = 'none'; currentIndex = images.length; slidesContainer.style.transform = `translateX(${-slideWidth * currentIndex}px)`; } else if (currentIndex === images.length + 1) { // 末尾ダミーに来たら、本当の最初に瞬時に移動 slidesContainer.style.transition = 'none'; currentIndex = 1; slidesContainer.style.transform = `translateX(${-slideWidth * currentIndex}px)`; } }; // **自動スライド開始** const startAutoPlay = () => { autoSlide = setInterval(() => { moveSlide(currentIndex + 1); }, 3000); }; // **オートスライド停止** const stopAutoPlay = () => clearInterval(autoSlide); // **オートスライド再開** const restartAutoPlay = () => { stopAutoPlay(); startAutoPlay(); }; // **初期セットアップ** const init = () => { slidesContainer.style.transform = `translateX(${-slideWidth * currentIndex}px)`; startAutoPlay(); }; // **イベントリスナー** document.querySelector('.next').addEventListener('click', () => { moveSlide(currentIndex + 1); restartAutoPlay(); }); document.querySelector('.prev').addEventListener('click', () => { moveSlide(currentIndex - 1); restartAutoPlay(); }); slidesContainer.addEventListener('transitionend', resetPosition); window.addEventListener('load', init);
JavaScriptコードの流れと詳細な解説
このコードは JavaScript だけでダミー画像を生成し、無限ループする横スライドを実現 しています。
1.画像データの用意
const images = [ "https://placehold.jp/410042/ffffff/800x400.jpg?text=slide01", "https://placehold.jp/ffcb5c/ffffff/800x400.jpg?text=slide02", "https://placehold.jp/4991ee/ffffff/800x400.jpg?text=slide03" ];
スライドで表示する画像のURLを images
配列に格納。相対アドレス(images/slide.jpg)でもOK
2.スライド要素の作成
const slidesContainer = document.querySelector('.slides');
HTMLに設定してある.slides
内に img
要素を追加するために、要素を取得。
3.JavaScript でスライド要素を自動生成
const createSlideElements = () => { // ダミーとして最後の画像を最初に追加 const firstDummy = document.createElement('img'); firstDummy.src = images[images.length - 1]; // 最後の画像 slidesContainer.appendChild(firstDummy); // 実際の画像を追加 images.forEach(src => { const img = document.createElement('img'); img.src = src; slidesContainer.appendChild(img); }); // ダミーとして最初の画像を最後に追加 const lastDummy = document.createElement('img'); lastDummy.src = images[0]; // 最初の画像 slidesContainer.appendChild(lastDummy); };
ダミー画像を追加することで無限ループを可能にする
- 最初に「最後の画像」を追加 → これがダミー画像となる。
- 配列の画像をすべて追加 → 実際のスライド画像を生成。
- 最後に「最初の画像」を追加 → これがダミー画像となる。
生成されたHTML↓
<div class="slides"> <img src="slide03.jpg"> <!-- ダミー(最後の画像) --> <img src="slide01.jpg"> <!-- 実画像1 --> <img src="slide02.jpg"> <!-- 実画像2 --> <img src="slide03.jpg"> <!-- 実画像3 --> <img src="slide01.jpg"> <!-- ダミー(最初の画像) --> </div>
4.スライドの動作を制御
const slideImages = document.querySelectorAll('.slides img'); let currentIndex = 1; // 実際のスライド開始位置(1枚目の画像) const slideWidth = 800; // スライドの幅 let autoSlide;
slideImages
→ 追加した画像リストを取得。currentIndex
→ スライドの初期位置を1 に設定(0はダミーなので飛ばす)。slideWidth
→ 画像の横幅(ピクセル単位)。autoSlide
→ 自動スライド用のsetInterval
を管理。
5.スライドを移動する関数
const moveSlide = (index) => { slidesContainer.style.transition = 'transform 0.5s ease-in-out'; currentIndex = index; slidesContainer.style.transform = `translateX(${-slideWidth * currentIndex}px)`; };
指定した index
にスライドを移動
transform: translateX(-800px * index)
でスライドを横に移動。transition
を設定し、0.5秒間のアニメーション でスムーズに動くようにする。
6.無限ループのリセット処理
const resetPosition = () => { if (currentIndex === 0) { // 先頭ダミーに来たら、本当の最後に瞬時に移動 slidesContainer.style.transition = 'none'; currentIndex = images.length; slidesContainer.style.transform = `translateX(${-slideWidth * currentIndex}px)`; } else if (currentIndex === images.length + 1) { // 末尾ダミーに来たら、本当の最初に瞬時に移動 slidesContainer.style.transition = 'none'; currentIndex = 1; slidesContainer.style.transform = `translateX(${-slideWidth * currentIndex}px)`; } };
transitionend
で瞬時にリセット
- 先頭ダミー(index=0)に来たら → 本物の最後(
index=images.length
)へ瞬時に移動。 - 末尾ダミー(index=images.length+1)に来たら → 本物の最初(
index=1
)へ瞬時に移動。
この処理により、無限ループが自然に見えるようになる!
7.自動スライドの設定
const startAutoPlay = () => { autoSlide = setInterval(() => { moveSlide(currentIndex + 1); }, 3000); };
3秒ごとに moveSlide()
を実行し、自動でスライド
const stopAutoPlay = () => clearInterval(autoSlide);
clearInterval(autoSlide)
でオートスライドを停止
const restartAutoPlay = () => { stopAutoPlay(); startAutoPlay(); };
ユーザーがボタンを押したときに、自動スライドを再開
8.初期化処理
const init = () => { slidesContainer.style.transform = `translateX(${-slideWidth * currentIndex}px)`; startAutoPlay(); };
初期位置を設定し、自動スライドを開始
currentIndex = 1
の位置にセット。
9.ボタンイベントの追加
document.querySelector('.next').addEventListener('click', () => { moveSlide(currentIndex + 1); restartAutoPlay(); }); document.querySelector('.prev').addEventListener('click', () => { moveSlide(currentIndex - 1); restartAutoPlay(); });
「次へ」「前へ」ボタンの動作
moveSlide(currentIndex + 1)
で 次のスライドへ移動。moveSlide(currentIndex - 1)
で 前のスライドへ移動。restartAutoPlay()
を呼び出して 手動操作後も自動スライドが再開 するようにする。
10.transitionend
でリセット処理を実行
slidesContainer.addEventListener('transitionend', resetPosition);
スライドの移動が完了 (transitionend
発火) したら resetPosition()
を実行
- これにより、ダミー画像の位置調整が行われる。
11.ページロード時に init()
実行
window.addEventListener('load', init);
ページが読み込まれたら init()
を実行
- 初期位置にセットして、自動スライドを開始!