カルーセル(Carousel)を自作する方法
今回はカルーセル(写真のスライダー)を自作する方法を紹介します。
自作するにあたり以下のサイトを参考にしています。
サイト参考版
まず、一番シンプルに参考にしてきたサイトのコードそのまま利用した場合のバージョンになります。
サンプル
HTMLコード
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Slideshow / Carousel demo(1)</title>
<style type="text/css">
* {box-sizing:border-box}
/* Slideshow container */
.slideshow-container {
max-width: 1000px;
position: relative;
margin: auto;
}
/* Hide the images by default */
.mySlides {
display: none;
}
/* Next & previous buttons */
.prev, .next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
margin-top: -22px;
padding: 16px;
color: white;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
/* Position the "next button" to the right */
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
/* On hover, add a black background color with a little bit see-through */
.prev:hover, .next:hover {
background-color: rgba(0,0,0,0.8);
}
/* Caption text */
.text {
color: #f2f2f2;
font-size: 15px;
padding: 8px 12px;
position: absolute;
bottom: 8px;
width: 100%;
text-align: center;
}
/* Number text (1/3 etc) */
.numbertext {
color: #f2f2f2;
font-size: 12px;
padding: 8px 12px;
position: absolute;
top: 0;
}
/* The dots/bullets/indicators */
.dot {
cursor: pointer;
height: 15px;
width: 15px;
margin: 0 2px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
}
.active, .dot:hover {
background-color: #717171;
}
/* Fading animation */
.fade {
animation-name: fade;
animation-duration: 1.5s;
}
@keyframes fade {
from {opacity: .4}
to {opacity: 1}
}
</style>
</head>
<body>
<div style="width:50%">
<!-- Slideshow container -->
<div class="slideshow-container">
<!-- Full-width images with number and caption text -->
<div class="mySlides fade">
<div class="numbertext">1 / 3</div>
<img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06344.jpg" style="width:100%">
<div class="text">レッサーパンダ</div>
</div>
<div class="mySlides fade">
<div class="numbertext">2 / 3</div>
<img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07591.jpg" style="width:100%">
<div class="text">カピバラ</div>
</div>
<div class="mySlides fade">
<div class="numbertext">3 / 3</div>
<img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07708.jpg" style="width:100%">
<div class="text">ペンギン</div>
</div>
<!-- Next and previous buttons -->
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
</div><!-- slideshow-container -->
<br>
<!-- The dots/circles -->
<div style="text-align:center">
<span class="dot" onclick="currentSlide(1)"></span>
<span class="dot" onclick="currentSlide(2)"></span>
<span class="dot" onclick="currentSlide(3)"></span>
</div>
</div>
<script type="text/javascript">
let slideIndex = 1;
showSlides(slideIndex);
// Next/previous controls
function plusSlides(n) {
showSlides(slideIndex += n);
}
// Thumbnail image controls
function currentSlide(n) {
showSlides(slideIndex = n);
}
function showSlides(n) {
let i;
let slides = document.getElementsByClassName("mySlides");
let dots = document.getElementsByClassName("dot");
if (n > slides.length) {slideIndex = 1}
if (n < 1) {slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex-1].style.display = "block";
dots[slideIndex-1].className += " active";
}
</script>
</body>
</html>
デモ
実装方法
スタイルシート定義
<style type="text/css">
* {box-sizing:border-box}
/* Slideshow container */
.slideshow-container {
max-width: 1000px;
position: relative;
margin: auto;
}
/* Hide the images by default */
.mySlides {
display: none;
}
/* Next & previous buttons */
.prev, .next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
margin-top: -22px;
padding: 16px;
color: white;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
/* Position the "next button" to the right */
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
/* On hover, add a black background color with a little bit see-through */
.prev:hover, .next:hover {
background-color: rgba(0,0,0,0.8);
}
/* Caption text */
.text {
color: #f2f2f2;
font-size: 15px;
padding: 8px 12px;
position: absolute;
bottom: 8px;
width: 100%;
text-align: center;
}
/* Number text (1/3 etc) */
.numbertext {
color: #f2f2f2;
font-size: 12px;
padding: 8px 12px;
position: absolute;
top: 0;
}
/* The dots/bullets/indicators */
.dot {
cursor: pointer;
height: 15px;
width: 15px;
margin: 0 2px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
}
.active, .dot:hover {
background-color: #717171;
}
/* Fading animation */
.fade {
animation-name: fade;
animation-duration: 1.5s;
}
@keyframes fade {
from {opacity: .4}
to {opacity: 1}
}
</style>
まず、デフォルトのスタイルシートをコピーして定義します。
HTMLマークアップ
まず、カルーセル領域を生成し、classに『slideshow-container』を設定します。
<div class="slideshow-container">
...
</div>
次に各スライド領域を設定していきます。
<div class="slideshow-container">
<div class="mySlides fade">
<div class="numbertext">1 / 3</div>
<img src="(画像URI)" style="width:100%">
<div class="text">(キャプション)</div>
</div>
...
</div>
次に、DIV領域を生成し、class『mySlides』を設定します。
その配下に、画像のインデックス番号領域をDIVで生成し、項目番号を設定してください。classには『numbertext』を設定してください。
次に表示したい画像をイメージタグ(<img>)で設定してください。
もし、キャプションを設定したければ、その下にさらにDIV領域を生成し、class『text』を設定してください。
次・前ボタン設置
カルーセルの中にスライドを移動させるボタンを設置する場合には、以下のコードを追加します。
<div class="slideshow-container">
<div class="mySlides fade">
<div class="numbertext">1 / 3</div>
<img src="(画像URI)" style="width:100%">
<div class="text">(キャプション)</div>
</div>
...
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
</div>
class『prev』を設定すると、ボタンが左に固定されます。
class『next』を設定すると、ボタンが右に固定されます。
ドット/サークル設置
カルーセルの下部に、ドット/サークルを設置し、スライド数やカレントの状態を表示させることができます。以下のコードを追加してください。
<div class="slideshow-container">
<div class="mySlides fade">
<div class="numbertext">1 / 3</div>
<img src="(画像URI)" style="width:100%">
<div class="text">(キャプション)</div>
</div>
...
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
</div>
<br>
<!-- The dots/circles -->
<div style="text-align:center">
<span class="dot" onclick="currentSlide(1)"></span>
...
</div>
class『dot』を設定すると丸いドット画像が設定されます。
Javascriptコード追加
<script type="text/javascript">
let slideIndex = 1;
showSlides(slideIndex);
// Next/previous controls
function plusSlides(n) {
showSlides(slideIndex += n);
}
// Thumbnail image controls
function currentSlide(n) {
showSlides(slideIndex = n);
}
function showSlides(n) {
let i;
let slides = document.getElementsByClassName("mySlides");
let dots = document.getElementsByClassName("dot");
if (n > slides.length) {slideIndex = 1}
if (n < 1) {slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex-1].style.display = "block";
dots[slideIndex-1].className += " active";
}
</script>
最後のJavascriptコードを追加することで、カルーセルが設定されます。
ドット/サークルおよびスライド数自動生成してみた
ドット数やスライドの項目数をひとつひとつ設定するのは面倒なので、自動生成するようなコードを作成してみました。
HTMLコード
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Slideshow / Carousel demo(2)</title>
<style type="text/css">
* {box-sizing:border-box}
/* Slideshow container */
.slideshow-container {
max-width: 1000px;
position: relative;
margin: auto;
}
/* Hide the images by default */
.mySlides {
display: none;
}
/* Next & previous buttons */
.prev, .next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
margin-top: -22px;
padding: 16px;
color: white;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
/* Position the "next button" to the right */
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
/* On hover, add a black background color with a little bit see-through */
.prev:hover, .next:hover {
background-color: rgba(0,0,0,0.8);
}
/* Caption text */
.text {
color: #f2f2f2;
font-size: 15px;
padding: 8px 12px;
position: absolute;
bottom: 8px;
width: 100%;
text-align: center;
}
/* Number text (1/3 etc) */
.numbertext {
color: #f2f2f2;
font-size: 12px;
padding: 8px 12px;
position: absolute;
top: 0;
}
/* The dots/bullets/indicators */
.dot {
cursor: pointer;
height: 15px;
width: 15px;
margin: 0 2px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
}
.active, .dot:hover {
background-color: #717171;
}
/* Fading animation */
.fade {
animation-name: fade;
animation-duration: 1.5s;
}
@keyframes fade {
from {opacity: .4}
to {opacity: 1}
}
</style>
</head>
<body>
<div style="width:50%">
<!-- Slideshow container -->
<div class="slideshow-container">
<!-- Full-width images with number and caption text -->
<div class="mySlides fade">
<img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06344.jpg" style="width:100%">
<div class="text">レッサーパンダ</div>
</div>
<div class="mySlides fade">
<img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07591.jpg" style="width:100%">
<div class="text">カピバラ</div>
</div>
<div class="mySlides fade">
<img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07708.jpg" style="width:100%">
<div class="text">ペンギン</div>
</div>
<div class="mySlides fade">
<img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06513.jpg" style="width:100%">
<div class="text">ネコ</div>
</div>
<!-- Next and previous buttons -->
<a class="prev">❮</a>
<a class="next">❯</a>
</div><!-- slideshow-container -->
<br>
</div>
<script type="text/javascript">
var myCarousel = document.querySelector(".slideshow-container");
var slides = document.querySelectorAll(".slideshow-container div img");
if ( slides != undefined ) {
var nCount = slides.length;
if ( nCount > 0 ) {
var dotArea = document.createElement("div");
dotArea.style.textAlign = 'center';
for ( var i=0; i < nCount; i++ ) {
var imgObj = slides[i];
var slide = slides[i].parentElement;
var photoIndex = document.createElement("div");
photoIndex.className = 'numbertext';
photoIndex.innerHTML = String(i+1) + " / " + String(nCount);
slide.insertBefore(photoIndex,imgObj);
/* ドット/サークル作成 */
var dotCircle = document.createElement("span");
dotCircle.className = "dot";
/* イベント設定 */
setClickEvent(i+1,dotCircle);
dotArea.appendChild(dotCircle);
}
myCarousel.parentElement.appendChild(dotArea);
}
}
/* 前ボタンのアクション */
var btnPrev = document.querySelector(".prev");
setBtnClickEvent(-1,btnPrev);
/* 次ボタンのアクション */
var btnNext = document.querySelector(".next");
setBtnClickEvent(1,btnNext);
let slideIndex = 1;
showSlides(slideIndex);
// Next/previous controls
function plusSlides(n) {
showSlides(slideIndex += n);
}
// Thumbnail image controls
function currentSlide(n) {
showSlides(slideIndex = n);
}
function showSlides(n) {
let i;
let slides = document.getElementsByClassName("mySlides");
let dots = document.getElementsByClassName("dot");
if (n > slides.length) {slideIndex = 1}
if (n < 1) {slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex-1].style.display = "block";
dots[slideIndex-1].className += " active";
setTimeout(showSlides, 2000); // Change image every 2 seconds
}
function setClickEvent(idx,dotCircle) {
/* ドットクリック時のイベント設定 */
dotCircle.addEventListener( 'click', function() {
currentSlide(idx);
}, false );
}
function setBtnClickEvent(increment,btn) {
if ( btn == undefined ) return;
/* ボタンクリック時のイベント設定 */
btn.addEventListener( 'click', function() {
plusSlides(increment);
}, false );
}
</script>
</body>
</html>
デモ
デモページでは項目数を4つにし、ドット/サークルや項目数を自動設定するようにしてあります。
実装方法
ドット/サークルの生成と項目数は実装不要になったので、スライド領域に写真とキャプションを設定するだけになります。
<div class="slideshow-container">
<div class="mySlides fade">
<img src="(画像URI)" style="width:100%">
<div class="text">(キャプション)</div>
</div>
...
<a class="prev">❮</a>
<a class="next">❯</a>
</div>
<br>
また、次・前へボタンについては、Javascriptでイベントを設定しているのでJavascript関数『plusSlides()』を設定しなくてもいいです。
スライドショー自動実行
<script type="text/javascript">
function showSlides(n) {
let i;
let slides = document.getElementsByClassName("mySlides");
let dots = document.getElementsByClassName("dot");
if (n > slides.length) {slideIndex = 1}
if (n < 1) {slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex-1].style.display = "block";
dots[slideIndex-1].className += " active";
setTimeout(showSlides, 2000); // Change image every 2 seconds
}
</script>
関数「showSlides」に、setTimeoutで同じ関数を2秒ごとに呼び出すようにしてあります。
カルーセルをライブラリ化してみた
最後に、サンプルのカルーセルを実装してくれるクラスを自作してみました。
サンプル
HTMLコード
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Slideshow / Carousel demo(3)</title>
<link rel="stylesheet" href="https://www.single-life.tokyo/demo/MyCarousel.css">
<style type="text/css">
.numbertext {
font-size: 64px;
}
</style>
</head>
<body>
<div style="width:50%">
<!-- Slideshow container -->
<div class="slideshow-container myCarousel">
<!-- Full-width images with number and caption text -->
<div class="mySlides fade">
<img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06344.jpg" style="width:100%">
<div class="text">レッサーパンダ</div>
</div>
<div class="mySlides fade">
<img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07591.jpg" style="width:100%">
<div class="text">カピバラ</div>
</div>
<div class="mySlides fade">
<img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07708.jpg" style="width:100%">
<div class="text">ペンギン</div>
</div>
<div class="mySlides fade">
<img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06513.jpg" style="width:100%">
<div class="text">ネコ</div>
</div>
<!-- Next and previous buttons -->
<a class="prev">❮</a>
<a class="next">❯</a>
</div><!-- slideshow-container -->
<br>
</div>
<script src="https://www.single-life.tokyo/demo/MyCarousel.js"></script>
<script type="text/javascript">
/* interval:スライドの表示時間(ミリ秒) */
/* slideIndex:初期表示時のスライド番号(1~) */
/* dotVisible:falseにするとドットが非表示 */
var carousel = new MyCarousel(".myCarousel",{ interval:4000, slideIndex:2 } );
</script>
</body>
</html>
CSSファイル(MyCarousel.css)
* {box-sizing:border-box}
/* Slideshow container */
.slideshow-container {
max-width: 1000px;
position: relative;
margin: auto;
}
/* Hide the images by default */
.mySlides {
display: none;
}
/* Next & previous buttons */
.prev, .next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
margin-top: -22px;
padding: 16px;
color: white;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
/* Position the "next button" to the right */
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
/* On hover, add a black background color with a little bit see-through */
.prev:hover, .next:hover {
background-color: rgba(0,0,0,0.8);
}
/* Caption text */
.text {
color: #f2f2f2;
font-size: 15px;
padding: 8px 12px;
position: absolute;
bottom: 8px;
width: 100%;
text-align: center;
}
/* Number text (1/3 etc) */
.numbertext {
color: #f2f2f2;
font-size: 12px;
padding: 8px 12px;
position: absolute;
top: 0;
}
/* The dots/bullets/indicators */
.dot {
cursor: pointer;
height: 15px;
width: 15px;
margin: 0 2px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
}
.active, .dot:hover {
background-color: #717171;
}
/* Fading animation */
.fade {
animation-name: fade;
animation-duration: 1.5s;
}
@keyframes fade {
from {opacity: .4}
to {opacity: 1}
}
JSファイル(MyCarousel.js)
class MyCarousel {
constructor(selector,options) {
/* オプション取得 */
this.selector = selector;
this.interval = options.interval || 0;
this.slideIndex = options.slideIndex || 1;
this.prevSelector = options.prevSelector || '.prev';
this.nextSelector = options.nextSelector || '.next';
this.dotClass = options.dotClass || 'dot';
this.numbertextClass = options.numbertextClass || 'numbertext';
this.dotAreaClass = options.dotAreaClass || 'dotArea';
this.slideSelector = options.slideSelector || '.mySlides';
if ( options.dotVisible == undefined ) this.dotVisible = true;
else this.dotVisible = options.dotVisible;
/* 初期化処理実行 */
this.init();
}
/* ラベルおよびドット設定 */
init() {
var myCarousel = document.querySelector(this.selector);
var slides = document.querySelectorAll(this.selector + " div img");
if ( slides != undefined ) {
var nCount = slides.length;
if ( nCount > 0 ) {
var dotArea = document.createElement("div");
dotArea.style.textAlign = 'center';
dotArea.className = "dotArea";
for ( var i=0; i < nCount; i++ ) {
var imgObj = slides[i];
var slide = slides[i].parentElement;
var photoIndex = document.createElement("div");
photoIndex.className = this.numbertextClass;
photoIndex.innerHTML = String(i+1) + " / " + String(nCount);
slide.insertBefore(photoIndex,imgObj);
if ( this.dotVisible ) {
/* ドット/サークル作成 */
var dotCircle = document.createElement("span");
dotCircle.className = this.dotClass;
/* イベント設定 */
this.setClickEvent(i+1,dotCircle);
dotArea.appendChild(dotCircle);
}
}
myCarousel.parentElement.appendChild(dotArea);
}
}
/* 前ボタンのアクション */
var btnPrev = document.querySelector(this.prevSelector);
this.setBtnClickEvent(-1,btnPrev);
/* 次ボタンのアクション */
var btnNext = document.querySelector(this.nextSelector);
this.setBtnClickEvent(1,btnNext);
/* 初期表示 */
this.showSlides(this.slideIndex);
if ( this.interval > 0 ) {
/* スライドショー実行 */
setInterval(() => {
this.plusSlides(1);
}, this.interval);
}
}
// Next/previous controls
plusSlides(n) {
this.showSlides(this.slideIndex += n);
}
// Thumbnail image controls
currentSlide(n) {
this.showSlides(this.slideIndex = n);
}
showSlides(n) {
let i;
let slides = document.querySelectorAll(this.slideSelector);
let dots = document.getElementsByClassName(this.dotClass);
if (n > slides.length) {this.slideIndex = 1}
if (n < 1) {this.slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[this.slideIndex-1].style.display = "block";
dots[this.slideIndex-1].className += " active";
}
setClickEvent(idx,dotCircle) {
/* ドットクリック時のイベント設定 */
dotCircle.addEventListener( 'click', function() {
this.currentSlide(idx);
}.bind(this), false );
}
setBtnClickEvent(increment,btn) {
if ( btn == undefined ) return;
/* ボタンクリック時のイベント設定 */
btn.addEventListener( 'click', function() {
this.plusSlides(increment);
}.bind(this), false );
}
}
デモ
実装方法
MyCarousel初期化
<script type="text/javascript">
/* interval:スライドの表示時間(ミリ秒) */
/* slideIndex:初期表示時のスライド番号(1~) */
/* dotVisible:falseにするとドットが非表示 */
var carousel = new MyCarousel(".myCarousel",{ interval:4000, slideIndex:2 } );
</script>
MyCarouselクラスというのを作成しました。
初期化パラメータの第1パラメータに、スライドショー領域のセレクタ文字列、第2パラメータにオプションを指定できるようにしました。
以上、ご参考まで
ご参考
関連記事
- Fancybox v5でカルーセル(Carousel)を作る方法
- Bootstrapでカルーセル(Carousel)を作る方法
- jQueryプラグイン「Owl Carousel 2」を使ってカルーセル/スライダーを設定する方法
- カルーセル(Carousel)を自作する方法
- 「Shoelace」でカルーセル(Carousel)を作成する方法
- スライドショーギャラリー(Slideshow Gallery)を自作する方法
- スライダープラグイン「slick」の紹介
- スライダープラグイン「Flickity」の紹介