CommentOut

【CSS・javascript】カルーセルの作り方を3パターンで解説! 【CSS・javascript】カルーセルの作り方を3パターンで解説!

【CSS・javascript】カルーセルの作り方を3パターンで解説!

公開日:  最終更新日:

皆さんはカルーセルってどうやって作りますか?
カルーセルっていろんな動き方があって、それぞれ作り方が違うと思うんです。

カルーセルの作り方パターン1:javascript(jQuery)を使って1つずつ要素を入れ替える

私は最初に考えました。
『カルーセルエリアの先頭要素をjavascriptを使って一番後ろに移動させればいいんだ!』
要素そのものを動かすイメージです。

図解するとこんなイメージです。

このような要素の入れ替えにはjQueryのappendが使えます。
使い方は以下のような感じ

// elementの末尾に{要素}を追加する
$(element).append({要素});

// elementの先頭に{要素}を追加する
$(element).prepend({要素});

実際に動作するカルーセルのサンプルを作りました。

See the Pen Javascriptによるカルーセル by Uilou (@uilou754) on CodePen.

【HTML】

<div class="carousel_area">
    <!-- カルーセルさせる要素リスト -->
    <div class="carousel_area__inner">
        <div class="carousel_block">~~~</div>
        <div class="carousel_block">~~~</div>
        <div class="carousel_block">~~~</div>
        <div class="carousel_block">~~~</div>
        <div class="carousel_block">~~~</div>
    </div>
    <!-- 前に戻るボタン -->
    <div class="control__btn control__btn--prev">前</div>
    <!-- 次に進むボタン -->
    <div class="control__btn control__btn--next">次</div>
</div>

【CSS】

// 一番外側のdiv
.carousel_area {
    position: relative;
    // 今回、要素がエリア外に出るため、
    // 横スクロールバーが出ないようにはみ出た部分は非表示にします
    overflow: hidden;
}

// カルーセルする要素1つ分のブロック
.carousel_block {
    display: block;
    width: 280px;
    position: absolute;
    top: 50%;
    transform: translate(-50%, -50%);
}

// ブロック1つ目
.carousel_block:nth-of-type(1) { transform: translate(-50%, -50%); }
// ブロック2つ目
.carousel_block:nth-of-type(2) { transform: translateX(110%) translate(-50%, -50%); }
// ブロック3つ目
.carousel_block:nth-of-type(3) { transform: translateX(220%) translate(-50%, -50%); }
// ブロック4つ目
.carousel_block:nth-of-type(4) { transform: translateX(330%) translate(-50%, -50%); }
// ブロック5つ目
.carousel_block:nth-of-type(5) { transform: translateX(440%) translate(-50%, -50%); }

// 前・次ボタン - 共通部分
.control__btn {
    display: flex;
    position: absolute;
    top: 50%;
    z-index: 10;

    justify-content: center;
    align-items: center;
    transform: translate(-50%, -50%);
}
// 前ボタン
.control__btn--prev { left: 5%; }
// 次ボタン
.control__btn--next { left: 95%; }

コードが長くなるので、必要な部分のみ書いてます。
影とか背景色とか見た目に関する部分は消してるので、CodePenを見てください。

カルーセルブロックのtranslateX(110%);とかtranslateX(220%);は最初の要素からどれくらい離すかという指定をしていて、1個分だとくっついて表示されてしまうため、1.1個分、2.2個分離してくださいね。という意味です。
上下中央を説明してる記事でも書いたのですが、transform: translateの移動量を%で指定した時、移動量はその要素の大きさに依存するため、その機能を利用して位置をずらしています。
上下中央揃えなどを紹介している記事は下記リンクを参照ください。

記述するjavascriptも単純です。

【javascript(jQuery)】

$(function() {
    // 2秒ごとに次の要素に移動させる
    setInterval(next, 2000);

    $('.control__btn--prev').on('click', prev);
    $('.control__btn--next').on('click', next);
});

// カルーセルリストの先頭の要素を末尾に挿入する
function next() {
    $('.carousel_area__inner').append($('.carousel_area__inner > .carousel_block:first-child'));
}
// カルーセルリストの末尾の要素を先頭に挿入する
function prev() {
    $('.carousel_area__inner').prepend($('.carousel_area__inner > .carousel_block:last-child'));
}

jQueryで要素を入れ替えるには、appendとprependを使用します。
これらを使うことで、簡単に要素を入れ替えることができます。

// .carousel_blockの先頭要素を.carousel_area__innerの最後に挿入する
$('.carousel_area__inner').append($('.carousel_area__inner > .carousel_block:first-child'));

// .carousel_blockの最後の要素を.carousel_area__innerの先頭に挿入する
$('.carousel_area__inner').prepend($('.carousel_area__inner > .carousel_block:last-child'));

append()やprepend()の挙動について

jQueryのappend()やprepend()って、元々要素を末尾、もしくは先頭に挿入する関数なのですが、このように『.carousel_area__innerの中の要素を同じ.carousel_area__innerに挿入する』と記述することで、元々あった.carousel_blockが削除され、先頭もしくは末尾に要素が挿入されます

<ul class="list">
    <li>リスト01</li>
    <li>リスト02</li>
    <li>リスト03</li>
</ul>

<script>
    $('.list').append('<li>末尾!</li>');
</script>

このように、append()の中にタグをベタ書きすると、べた書きしたタグが指定した要素(.list)の末尾に追加されます。
javascriptが実行された後は、以下のようになります。

<ul class="list">
    <li>リスト01</li>
    <li>リスト02</li>
    <li>リスト03</li>
    <li>末尾!</li>
</ul>

ただし、このappendの中にDOMの要素を指定した場合は挙動が変わります。

<ul class="list">
    <li>リスト01</li>
    <li>リスト02</li>
    <li>リスト03</li>
</ul>

<script>
    $('.list').append($('.list:first-child'));
</script>

append, appendTo, prepend, prependToは、上記のようにDOM要素を指定することで、指定されたDOM要素を削除する動きをします。
上記のjavascriptが実行されると、以下のようになります。

<ul class="list">
    <li>リスト02</li>
    <li>リスト03</li>
    <li>リスト01</li>
</ul>

追加ではなく、移動になってしまうんですね。
今回は要素を移動させたかったので、これでいいんですが、もし要素をコピーして追加したい場合は、cloneを作って、cloneをappendするようにしたら、元のDOM要素は削除されず残ります。

<ul class="list">
    <li>リスト01</li>
    <li>リスト02</li>
    <li>リスト03</li>
</ul>

<script>
    $('.list').append($('.list:first-child').clone(true));
</script>

このように、appendに渡すDOM要素に、clone()の戻り値を渡すようにしたら、元のDOM要素には影響を与えないのです。

しかし、動作サンプルを見てもらうとわかるのですが、確かにjQueryによって要素は入れ替わっていますが、要素の位置が入れ替わったとしても、一瞬で入れ替わるのでカルーセルっぽくないんですよね。

アニメーションしない理由として、DOM自体をいじっているため、CSSのtransitionやanimationが動作しないんです。
これではカルーセルとは呼べませんね。

カルーセルの作り方パターン2:CSSを使って、横並びにした要素の位置をずらす

また私は考えました。
『アニメーションさせるなら、カルーセル要素を全て横並びにして、親要素ごと横にずらしてしまえばカルーセルっぽくなるじゃん!』

以下のサンプルでは下部の丸をクリックすると、カルーセルがスライドします

See the Pen 親要素をずらすことによるカルーセル by Uilou (@uilou754) on CodePen.

今回はカルーセルする要素を囲っているdivを2重構造にしています。
どういう動きをしているか図解すると、以下のようなイメージです。

【HTML】

<div class="carousel_area">
	<div class="carousel_area__inner position01">
		<div class="carousel_block">~~~</div>
		<div class="carousel_block">~~~</div>
		<div class="carousel_block">~~~</div>
		<div class="carousel_block">~~~</div>
		<div class="carousel_block">~~~</div>
	</div>
</div>

<div class="carousel_buttons">
	<div class="carousel_button" data-num="01"></div>
	<div class="carousel_button" data-num="02"></div>
	<div class="carousel_button" data-num="03"></div>
	<div class="carousel_button" data-num="04"></div>
	<div class="carousel_button" data-num="05"></div>
</div>

【CSS】

.carousel_area {
    position: relative;
    overflow: hidden;
}
.carousel_area__inner {
    width: calc(300px * 5);
    position: relative;
    top: 0px;
    left: 0px;
		
    // スライドアニメーションさせるため
    transition: left 0.5s ease;
}
.carousel_area__inner.position01 { left: calc(-300px * 0); }
.carousel_area__inner.position02 { left: calc(-300px * 1); }
.carousel_area__inner.position03 { left: calc(-300px * 2); }
.carousel_area__inner.position04 { left: calc(-300px * 3); }
.carousel_area__inner.position05 { left: calc(-300px * 4); }
	
.carousel_block {
    display: inline-block;
    margin-right: 20px;
    width: 280px;
}

さきほどの図で言うと、.carousel_areaが外側の枠で、.carousel_area__innerが内側の枠です。
.carousel_area__innerの中の要素は全て横並びになっていてほしいので、widthをcalc(300px * 5)にしています。
内部コンテンツがwidth: 280px + margin-right: 20px = 300pxになるためです。
もしくは、display: flex;にしてしまうとかですかね。

今回はずれる量をCSSで設定しているので、javascriptは単純にクラスの付け替えを行っているのみです。

$('.carousel_button').on('click', function() {
    $('.carousel_area__inner').removeClass('position01 position02 position03 position04 position05');
    $('.carousel_area__inner').addClass('position'+$(this).data('num'));
});

今回はカスタムデータ属性を使ってみました。
それぞれのカルーセルを動かすボタンにあらかじめカスタムデータ属性で番号を仕込んでおきます。
そしてクリックされたら、クリックされたボタンのカスタムデータ属性をクラス名につけてやることで、所定のクラスを付けることができます。

しかし、親要素ごとずらしているだけなので、最後までカルーセルを動かした時、ループしないんですよね。
ループさせるにはどうしたらいいんでしょうか。

カルーセルの作り方パターン3:要素を横にスライドさせ、端まで到達したら反対側に移動させることで、ループさせる

カルーセルで要素をループさせようと思ったら、考え方としては2通りしかないと思います。

1つは上記のスライドするやつの進化系で、内部要素をコピーして入れ替えてやる方法です。
図にすると以下のようなイメージです。

これは要素の塊ごと動かすパターンですが、もう一つ、最初の要素を入れ替えていた物に似ているのですが、各要素にクラスを付けて、クラスを循環的に入れ替えてやる方法があります。
先ほど失敗したように、要素そのものを動かすと、transitionが効かないんですね。
なので、要素を動かすのではなく、要素のクラスを付け替えてやろう!という作戦です。
以下のコードを見てください。

【HTML】

<div class="carousel_area">
	<div class="carousel_block carousel_block--01">~~~</div>
	<div class="carousel_block carousel_block--02">~~~</div>
	<div class="carousel_block carousel_block--03">~~~</div>
	<div class="carousel_block carousel_block--04">~~~</div>
	<div class="carousel_block carousel_block--05">~~~</div>
</div>

【CSS】

$(function() {
	setInterval(function() {
		var block01 = $(".carousel_block--01");
		var block02 = $(".carousel_block--02");
		var block03 = $(".carousel_block--03");
		var block04 = $(".carousel_block--04");
		var block05 = $(".carousel_block--05");
		block01.removeClass("carousel_block--01").addClass("carousel_block--02");
		block02.removeClass("carousel_block--02").addClass("carousel_block--03");
		block03.removeClass("carousel_block--03").addClass("carousel_block--04");
		block04.removeClass("carousel_block--04").addClass("carousel_block--05");
		block05.removeClass("carousel_block--05").addClass("carousel_block--01");
	}, 2000);
});

jQueryでクラスを付け替えているのですが、よく見るとクラスが循環しているんです。
このクラスが循環することで、カルーセルの動きを作っています。

ただ循環させているだけではなく、一番初めの.carousel_block–01と、一番最後の.carousel_block–05はopacityが0になっています。
これは先頭から終端に要素の位置が移動する時、もしくはその逆の動きをする時には、要素がカルーセルエリア内を横切るため、それを透明化して見えないようにしているだけです。

See the Pen クラスを入れ替えることによるカルーセル by Uilou (@uilou754) on CodePen.

これが最終的なカルーセルの理想形なんじゃないでしょうか。
みなさんも自身のカルーセル最適解を見つけてみてください。

宣伝
WordPressサイトのテンプレート編集やトラブル対応、バグ修正、簡単なJavascriptの作成(カルーセルやバリデーション等)など、小規模なスポット対応を受け付けております。
もしお困りごとがありましたら、お問い合わせフォームよりご相談ください。

この記事を書いた人

uilou

uilou

プログラマー

基本的に、自分自身の備忘録のつもりでブログを書いています。 自分と同じ所で詰まった人の助けになれば良いかなと思います。 システムのリファクタリングを得意としており、バックエンド、フロントエンド、アプリケーション、SQLなど幅広い知識と経験があります。 広いだけでなく、知識をもっと深堀りしていきたいですね。