【コピペしながら理解する】自作JavaScriptスライダー

HTMLやCSSのようなマークアップ言語と呼ばれるものは、他の言語と比べ独学でも内容を理解する難易度は高くないと言われています。

しかし、JavaScriptやRuby、Pythonのようなプログラミング言語を独学で理解しようとすると、大きく難易度は上がります。

身近な知識のある人に教えてもらうのが一番ですが、「人にプログラミングを教えられるレベルの人は忙しくて教える時間がない」というジレンマもあります。

また、独学によくある話として、「わからないことを検索してネットの記事を読んでも、書かれている用語がわからないので理解できない」ということも聞きます。

それだけ最初の頃は理解の壁が大きいのでしょう。

これは非常によくわかります。

そこで、今回は「私がJavaScript学習を始めた初期になんとか自作したスライダー」を紹介・解説すれば、同じような独学の方の参考になるのではと考えました。

ベテランの合理的なコードに理解が追いつかない場合もあるからです。

ただ、つたないコードを共有するので、内容の試みとしてはメリットもデメリットもあるかと思います。

あくまで、初学者の方の理解を早める手助けとなれば幸いです。

目次

完成系デモ

まずは完成形のデモです。

0.5倍あたりが見やすいかと思いますので、下部分のボタンで調節してください。

See the Pen by shinobi (@shinobi-hattori) on CodePen.

以前私が制作したのは、このようなシンプルな4画面スライダーです。

スライドの現在地の表示をしている画面下部の丸い部分の「インジケーター」を連動させたり、自動でスライドする機能を実装する部分が少し難しいポイントです。

まずはHTMLとCSS

基本となる見た目をHTMLとCSSで作っていきます。

必要となるものは、

・スライドコンテンツ4画面
・左右のボタン
・下部分のインジケーター

の3つです。

各所のポイントを簡単に解説していきます。

コンテンツ部分

スライドのコンテンツに関してはサイト制作のトップページ画面最初に表示されるコンテンツを想定しており、画面幅は全画面表示の100vwに設定しています。

また、スライド機能の仕組みとして、横長の親要素でコンテンツを囲み、その親要素を動かしていく方法を使っています。

bodyの画面外に出たものをoverflow:hiddenで表示しないようにしていますが、実際は下の画像のようになっています。

左右のボタン

こちらのボタンは擬似要素で矢印を作り、position:absoluteで好きな箇所に置くだけです。

画像の上に被るような配置にしているので、普段は画像の邪魔にならないようにマウスオーバー時にボタン要素が大きく表示されるようにしています。

インジケーター

コンテンツ下部のインジケーターも、同じく擬似要素で丸い型を作り、position:absoluteで好きな場所に配置しています。

最初に表示されている部分に連動して、一番左のインジケーターを黒く塗りつぶしています。

その他の部分は後ほどJavaScriptで制御するようにしています。

ここまでが以下の状態です。

See the Pen by shinobi (@shinobi-hattori) on CodePen.

JavaScriptを書く

いよいよスライドの機能を実装していきます。

左右のボタンの機能、インジケーター連動、自動スライドの順番で書いていきます。

左右のボタン

JavaScriptを記述する際に、HTMLから要素を呼び出して機能をつけていきますが、CSSのstyle指定と使い分けをするためにclass名を呼び出さず、新しくidで名前をつけたものを呼び出します。

コンテンツ要素を囲っているsliderクラスと、左右のボタンのクラスにわかりやすい名前でidをつけます。

id=”slider”やid=”prev”など、わかりやすい名前でidを追加

次に、それら3つの要素をJavaScriptの変数として定義して、いつでも呼び出せるようにしておきます。

HTMLからid要素を呼び出すのは、document.getElementById(‘ id名’)と記述する
var slide = document.getElementById(‘slider’);
var prev = document.getElementById(‘prev’);
var next = document.getElementById(‘next’);
のような形で、3つを定義していく

続いて、変数として定義した左右のボタンにクリックイベントを設定していきます。

クリックイベントを設定する方法もいくつかありますが、今回はaddEventListenerというものを使っていきます。

定義した変数.addEventListener(‘click’, 関数の名前);の記述で、クリックイベントの設定
関数の名前はわかりやすい名前を設定(デモではnextClickやprevClickという関数名に設定)
prev.addEventListener(‘click’, prevClick);
next.addEventListener(‘click’, nextClick);
でクリックしたときにそれぞれprevClickとnextClickが実行されるという機能がつく

上で設定したクリックイベントの関数名は、まだ中身が設定されていないので、何も実行されません。

関数prevClickとnextClickの中身を書いていきます。

あらかじめデモに書いてあるprevClick関数の内容を日本語で解説すると、

・prevがクリックされたときの関数であることの宣言
・クリックしたとき、sliderに「slider1」というclassが含まれていたら
・slider1というclassを削除して
・slider4というclassを追加する

というような4段階の内容になっています。

それぞれ実際の記述と当てはめていくと、

function prevClick() {
}
→prevがクリックされたときの関数であることの宣言

if (slide.classList.contains(‘slider1’) === true)
→クリックしたとき、sliderに「slider1」というclassが含まれていたら

slide.classList.remove(‘slider1’);
→slider1というclassを削除して

slide.classList.add(‘slider4’);
→slider4というclassを追加する

となります。

いわゆる「if文」でクリックされた際の条件を記述しています。

これらを組み合わせたものが以下になります。

function prevClick() {
if (slide.classList.contains(‘slider1’) === true) {
slide.classList.remove(‘slider1’);
slide.classList.add(‘slider4’);
}

ここで、slider1とslider4というclassをなぜ追加するのかという解説をしておきます。

実は、事前にCSSにはslider1〜slider4までのclassを作っておくことが今回のスライド機能の重要なポイントです。

slider1〜slider4にはそれぞれ以下のようなstyleをあてておきます。

.slider1 {
transform: translateX(0);
transition: all 0.3s;
}
.slider2 {
transform: translateX(-100vw);
transition: all 0.3s;
}
.slider3 {
transform: translateX(-200vw);
transition: all 0.3s;
}
.slider4 {
transform: translateX(-300vw);
transition: all 0.3s;
}

これらはどのような意味を持つのかというと、1行目のtransformというプロパティは、座標の移動を可能にするstyleです。

100vwが全画面いっぱいを表すので、一番上のslider1に設定されているtranslateX(0)は最初の画面のままという意味です。

slider2に設定されているtranslateX(-100vw)が、1画面分移動するという意味になっています。

つまり、それぞれ4画面の場所に移動できるようにCSSをあらかじめ書いているということです。

これがあれば、クリックされたとき今付与されているclassを解除して、指定する場所のslider番号のclassを追加して移動することができます。

また、transitionプロパティも記述すると、画面移動が瞬間の切り替わりではなくアニメーションも追加され、スライダーとしての見た目を作ることができます。

以上を踏まえ、初期画面ではsliderクラスにslider1を追加して書いておきます。

そして、slider2にいるときにクリックされた場合はslider2のクラスを解除して、隣の数字をクラスを追加するというものを追記し、これをslider3と4も書いていきます。

それぞれ全て記述したものが以下になります。

function prevClick() {
if (slide.classList.contains(‘slider1’) === true) {
slide.classList.remove(‘slider1’);
slide.classList.add(‘slider4’);
list1.style.backgroundColor = ‘transparent’;
list4.style.backgroundColor = ‘#000’;
count = 0;
} else if (slide.classList.contains(‘slider2’) === true) {
slide.classList.remove(‘slider2’);
slide.classList.add(‘slider1’);
list2.style.backgroundColor = ‘transparent’;
list1.style.backgroundColor = ‘#000’;
count = 0;
} else if (slide.classList.contains(‘slider3’) === true) {
slide.classList.remove(‘slider3’);
slide.classList.add(‘slider2’);
list3.style.backgroundColor = ‘transparent’;
list2.style.backgroundColor = ‘#000’;
count = 0;
} else {
slide.classList.remove(‘slider4’);
slide.classList.add(‘slider3’);
list4.style.backgroundColor = ‘transparent’;
list3.style.backgroundColor = ‘#000’;
count = 0;
}
};

ifとif elseで条件の分岐をしながら、4画面分のprevClick関数が書き終わりました。

これを、nextClick関数にも同じように記述していきます。

移動する方向が反対になるので、追加するclassの順番だけ注意が必要です。

以上で、左右のボタンのスライド機能を実装することができました。

See the Pen by shinobi (@shinobi-hattori) on CodePen.

インジケーター

コンテンツ下部に並んでいるインジケーターの機能を追加していきます。

インジケーターに追加したい機能は以下の2点です。

・スライドの動きに連動して、黒く塗りつぶされている場所も移動する
・インジケーター自体をクリックして、任意の場所にスライドできるようにする

まずはスライドと連動させるところからJavaScriptを書いていきます。

ボタンのときと同じように、最初は変数を定義していきます。

インジケーターはリスト構造になっていて、それぞれにlist1〜list4までidが付与されています。

これらを以下のように呼び出します。

var slide = document.getElementById(‘slider’);
var prev = document.getElementById(‘prev’);
var next = document.getElementById(‘next’);

//ボタンを記述した下に追加して書いていく
var list1 = document.getElementById(‘list1’);
var list2 = document.getElementById(‘list2’);
var list3 = document.getElementById(‘list3’);
var list4 = document.getElementById(‘list4’);

変数が呼び出せるようになったら、先ほどの左右のボタンの関数の中身に追加して条件を記述します。

内容は、
・現在のインジケーターの背景色を無色にする(transparentを指定すると無色になる)
・移動先のインジケーターの背景色に色を付ける

というものです。

変数.style.backgroundColor = ‘変更内容’;

という記述なので、わかりやすいと思います。

以下が、prevClickの関数内に追加して記述した内容です。

function prevClick() {
if (slide.classList.contains(‘slider1’) === true) {
slide.classList.remove(‘slider1’);
slide.classList.add(‘slider4’);
list1.style.backgroundColor = ‘transparent’;
list4.style.backgroundColor = ‘#000’;
} else if (slide.classList.contains(‘slider2’) === true) {
slide.classList.remove(‘slider2’);
slide.classList.add(‘slider1’);
list2.style.backgroundColor = ‘transparent’;
list1.style.backgroundColor = ‘#000’;
} else if (slide.classList.contains(‘slider3’) === true) {
slide.classList.remove(‘slider3’);
slide.classList.add(‘slider2’);
list3.style.backgroundColor = ‘transparent’;
list2.style.backgroundColor = ‘#000’;
} else {
slide.classList.remove(‘slider4’);
slide.classList.add(‘slider3’);
list4.style.backgroundColor = ‘transparent’;
list3.style.backgroundColor = ‘#000’;
}
};

同様に、nextClick関数にも追記すれば、スライド移動に対してインジケーターの色が連動する機能の実装が終了です。

次に、インジケーター自体をクリックした場合のスライド機能を実装していきます。

まずは各ボタンのクリックイベントを書いていきます。

こちらもaddEventListenerを利用します。

list1.addEventListener(‘click’, click1);
list2.addEventListener(‘click’, click2);
list3.addEventListener(‘click’, click3);
list4.addEventListener(‘click’, click4);

以上でクリックイベントが付与されました。

左右のボタンと同様に、名付けた関数にそれぞれ実行内容を書いていきます。

内容は、

・クリックされたインジケーターの番号と同じsliderクラスの番号を追加
・その他のクラスを全て解除
・クリックされたインジケーターの背景色を追加
・その他のインジケーターの背景色を無色にする

というものです。

左右のボタンで書いたようなクラスの追加と背景色の変更だけなので、内容はすでに簡単です。

function click1() {
slide.classList.add(‘slider1’);
slide.classList.remove(‘slider2’);
slide.classList.remove(‘slider3’);
slide.classList.remove(‘slider4’);
list1.style.backgroundColor = ‘#000’;
list2.style.backgroundColor = ‘transparent’;
list3.style.backgroundColor = ‘transparent’;
list4.style.backgroundColor = ‘transparent’;
}

function click2() {
slide.classList.remove(‘slider1’);
slide.classList.add(‘slider2’);
slide.classList.remove(‘slider3’);
slide.classList.remove(‘slider4’);
list1.style.backgroundColor = ‘transparent’;
list2.style.backgroundColor = ‘#000’;
list3.style.backgroundColor = ‘transparent’;
list4.style.backgroundColor = ‘transparent’;
}

function click3() {
slide.classList.remove(‘slider1’);
slide.classList.remove(‘slider2’);
slide.classList.add(‘slider3’);
slide.classList.remove(‘slider4’);
list1.style.backgroundColor = ‘transparent’;
list2.style.backgroundColor = ‘transparent’;
list3.style.backgroundColor = ‘#000’;
list4.style.backgroundColor = ‘transparent’;
}

function click4() {
slide.classList.remove(‘slider1’);
slide.classList.remove(‘slider2’);
slide.classList.remove(‘slider3’);
slide.classList.add(‘slider4’);
list1.style.backgroundColor = ‘transparent’;
list2.style.backgroundColor = ‘transparent’;
list3.style.backgroundColor = ‘transparent’;
list4.style.backgroundColor = ‘#000’;
}

それぞれのインジケーターの関数を書き終えたので、これでスライダーとしてはすでに十分な機能になりました。

現状がこちらです。

See the Pen by shinobi (@shinobi-hattori) on CodePen.

自動スライド

最後に、一定時間経ったら自動でスライドする機能をつけていきます。

時間を操作する書き方もいくつかありますが、今回はsetIntervalというものを使っていきます。

こちらも、まずは日本語で内容を書いてみます。

・setIntervalで、1秒ごとに実行される関数を書く
・count = 0という変数を定義し、setIntervalが実行されるたびに1ずつ数字を増やしていく
・setIntervalが実行される際、countの数字が4より大きい場合はcountを0に戻して、さらに関数のnextClickを実行する

このような内容を書いていきます。

書き方は以下のようなif文で表現することができます。

var count = 0;

setInterval(() => {
if (count > 4) {
count = 0;
nextClick();
}
count++;
console.log(count);
}, 1000);

記述されている最後の1000という数字が1秒を表しています。

setIntervalで設定する数字はミリセカンドである1000分の1秒表記なので、仮に10秒としたい場合は、10000と記述します。

今回は5秒ごとに自動でスライドされる機能を実装したいので、1秒ごとにsetIntervalを実行し、4より大きい数字、つまり5になればカウントをゼロに戻します。

カウントをゼロに戻すついでにスライドする関数のnextClickも実行していくようになっているので、5秒ごとに画面がスライドしていく機能が備わります。

また、setInterval関数の最後にconsole.log(count)という表記がありますので、ブラウザのデベロッパーツールを起動させると、コンソール画面に数字がカウントアップしていく様子を見ることができます。

以上で終わりたいところですが、このままだと自動でスライドされる機能と、ユーザーがクリックでスライドしたタイミングが同時だった場合、おかしな挙動をとってしまうことになります。

そこで、今まで記述してきたクリックイベントの中身にcount = 0 という記述を追記してあげます。

そうすることで、どこかがクリックされた際には、自動スライドのカウントアップをゼロに戻してあげることができます。

//prevボタンの場合
function prevClick() {
if (slide.classList.contains(‘slider1’) === true) {
slide.classList.remove(‘slider1’);
slide.classList.add(‘slider4’);
list1.style.backgroundColor = ‘transparent’;
list4.style.backgroundColor = ‘#000’;
count = 0; //ここに追記
} else if (slide.classList.contains(‘slider2’) === true) {
slide.classList.remove(‘slider2’);
slide.classList.add(‘slider1’);
list2.style.backgroundColor = ‘transparent’;
list1.style.backgroundColor = ‘#000’;
count = 0;//ここに追記
} else if (slide.classList.contains(‘slider3’) === true) {
slide.classList.remove(‘slider3’);
slide.classList.add(‘slider2’);
list3.style.backgroundColor = ‘transparent’;
list2.style.backgroundColor = ‘#000’;
count = 0;//ここに追記
} else {
slide.classList.remove(‘slider4’);
slide.classList.add(‘slider3’);
list4.style.backgroundColor = ‘transparent’;
list3.style.backgroundColor = ‘#000’;
count = 0;//ここに追記
}
};

以上で、全ての機能の実装が終わりました。

おつかれさまです。

もう一度完成デモを確認しながら、コードや動きの確認をしてみてください。

See the Pen by shinobi (@shinobi-hattori) on CodePen.

おわりに

今回は特にクライアントからの指定もなく、独学である私の最初のスライダー実装時のコードをシェアさせていただくコンセプトでした。

そのため、実際の現場で使うにはもっと綺麗な記述を求められる場合もありますので、あくまで初学時のプログラミング理解を手助けするものとして捉えていただければ幸いです。

以上、ハットリがお届けしました。@hattori_shinobi

TransitionとAnimationはどう使い分ける?使い方から解説【CSSアニメーション】 | shinobi
CSSアニメーションはTransitionとAnimationの2種類あるが、どう使い分けたらいいのか。基本的な使い方も含めて解説します。