webサイトのメインビジュアルによく使用される写真がスライドして切り替わるやつ。
あれを作ろうと思います。
プラグインのswiper.js(スワイパー)を使用すればかなりクオリティーの高いスライダーを作ることは可能ですが、プラグインのデメリットとして
- 余計な処理が入っており、動作重くなりがち
- 細かなカスタムが難しい
という点があります。
今回は プラグインを使用せずにスライダーを作る方法を紹介します。
製作物の確認:スライダーデモ
- 1〜5の画像があり、次へを押すと次の画像へ、前へを押すと前の画像へ
- 一番初めの画像が表示されている際に前へを押すと一番最後の画像を表示
- 一番最後の画像が表示されている際に次へを押すと一番最初の画像を表示
挙動については上記の通りです(スライドのスピードはお好みで)
この挙動をするスライダーを作って行きましょう。
結論
コードだけを知りたい方のために結論から書きます。
html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<div class="p-carousel js-carousel"> <div class="p-carousel__inner"> <ul class="p-carousel__list js-carousel-list"> <li class="p-carousel__item js-carousel-item"><img src="img/carousel_1.png"></li> <li class="p-carousel__item js-carousel-item"><img src="img/carousel_2.png"></li> <li class="p-carousel__item js-carousel-item"><img src="img/carousel_3.png"></li> <li class="p-carousel__item js-carousel-item"><img src="img/carousel_4.png"></li> <li class="p-carousel__item js-carousel-item"><img src="img/carousel_5.png"></li> </ul> </div> <nav class="p-carousel__index"> <div class="p-carousel__index-item"></div> </nav> <div class="p-carousel__btn"> <div class="p-carousel__prev js-carousel-prev">前へ</div> <div class="p-carousel__next js-carousel-next">次へ</div> </div> </div> |
css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
.p-carousel { position: relative; width: 600px; margin: 100px auto 0px auto; } .p-carousel__inner { overflow: hidden; width: 100%; height: 360px; } .p-carousel__list { display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-transform: translateX(0); transform: translateX(0); -webkit-transition: -webkit-transform 0.5s; transition: -webkit-transform 0.5s; transition: transform 0.5s; transition: transform 0.5s, -webkit-transform 0.5s; } .p-carousel__list img { width: 600px; height: 360px; } .p-carousel__index { width: 100%; height: 5px; margin: 0px; border: solid 1px #000; } .p-carousel__index-item { width: 0%; height: 100%; background-color: #888; } .p-carousel__btn { display: -webkit-box; display: -ms-flexbox; display: flex; -ms-flex-pack: distribute; justify-content: space-around; margin-top: 30px; } .p-carousel__prev, .p-carousel__next { background-color: rgba(0, 0, 0, 0); border: solid 1px #000; color: #000; width: 50px; text-align: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .p-carousel__prev:hover, .p-carousel__next:hover { background-color: #888; color: #fff; } |
js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
window.onload = function () { let transVal = 0; index = 1; indexNavVal = 0; const $listItem = $('.js-carousel-item'),//画像 $length = $listItem.length,//画像の枚数 $indexItem = $('.js-carousel__index-item'),//indexナビ $carouselList = $('.js-carousel-list'),//画像リスト $nextBtn = $('.js-carousel-next'),//次へ $prevBtn = $('.js-carousel-prev');//前へ indexNav(index,$length,$indexItem,indexNavVal); $nextBtn.on('click', function() { if(index == $length){ transVal = 0; index = 1; transform($carouselList,transVal); }else{ index = index + 1; transVal = transVal - 600; transform($carouselList,transVal); } indexNav(index,$length,$indexItem,indexNavVal); $('.p-sample__inner').addClass('-active'); }) $prevBtn.on('click', function() { if(index == 1){ transVal = ($length - 1) * -600; index = 5; transform($carouselList,transVal); }else{ index = index - 1; transVal = transVal + 600; transform($carouselList,transVal); }; indexNav(index,$length,$indexItem,indexNavVal); $('.p-sample__inner').removeClass('-active'); }); } function transform(carouselList,transVal){ carouselList.css( 'transform', 'translateX('+transVal+'px)' ); }; function indexNav(index,length,indexItem,indexNavVal){ indexNavVal = index/length * 100; indexItem.css( 'width', indexNavVal+'%' ); } |
解説
スライダーの仕組み
まずはスライダーがどのように再現されているのかを知る必要があります。
st1:画像横並びにした画像を用意します。
st2:その画像1枚分と同じ大きさの画像を見せたいエリアを用意します。
st3:表示させたいエリアにぶち込みます。
st4:画像を表示させたいエリア以外では画像を表示させたくないので、overflow:hidden;ではみ出たエリアを非表示にします。
すると現在の見た目は一番初めの画像、画像1のみが見える状態になります。
st5:あとは横並びにした画像群をtransletで動かしてしまえば画像がスライドして現れているように見えます。
作り方
jsでプログラムを組む際のおすすめの方法はまず、処理を日本語で考えるということです。
大事なものはロジックですのでそこを固め、プログラムを書くという行為はロジックの翻訳という感覚で行います。
今回はメインの処理としてスライダーの部分。サブの処理として何番目の画像が表示されているのかを表示するナビバー(名前は適当に命名したのであってるかわかりません)の部分に分けられます。
まずはメインの処理となるスライドの部分を作っていきましょう。
「次へ」「前へ」ボタンをそれぞれ押した場合の処理を考えていきます。
【メインの処理】「次へ」ボタンが押された場合
「次へ」が押されたことを検知
↓
横並びになった画像群を左に画像1枚分スライドさせたいのでcssのtransformの値を変更する
これでとりあえず画像をスライドさせることができます。
では翻訳しましょう。
翻訳はgoogleで調べます。
調べ方は「言語名 + やりたいこと」です。
「jquery クリックイベント」別タブで開きます
「jquery cssの変更」別タブで開きます
この情報を元に翻訳するとこうなりますね。
1 2 3 4 5 6 7 8 9 10 |
window.onload = function () { let transVal = 0; $('.js-carousel-next').on('click', function() { transVal = transVal - 600; $('.js-carousel-list').css( 'transform', 'translateX('+transVal+'px)' ); }); } |
window.onloadはhtmlの読み込みが終了したらカッコ内の処理を実行させるものです。
移動させる距離を保存する変数transValを作り、初期値に0を入れその変数を「次へ」がクリックされる毎に画像1枚分変更しています。
左に移動させたいので値はマイナスです。
↓
比較には現在表示している画像が何枚目なのかを知る必要があるので変数を用意し、画像がスライドする毎に変数の値を更新する
そして最後の画像が何枚目なのかを知る必要もあるので、画像全部の枚数を取得する
↓
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
window.onload = function () { let transVal = 0; index = 1; const $listItem = $('.js-carousel-item'),//画像 $length = $listItem.length;//画像の枚数 $('.js-carousel-next').on('click', function() { if(index == $length){ transVal = 0; index = 1; $('.js-carousel-list').css( 'transform', 'translateX('+transVal+'px)' ); }else{ index = index + 1; transVal = transVal -600; $('.js-carousel-list').css( 'transform', 'translateX('+transVal+'px)' ); } }); } |
現在の何枚目の画像を表示しているのかを保存する変数をindexとし、初めは、1枚目の画像を表示するので、indexに1を入れておきます。
そして最後の画像が何枚目なのかを知る必要もありますのでlengthという変数を作り、画像全部の枚数を取得して保存します。
もし、最後の画像だった場合、一番最初の画像に戻したいので、transValの値を0にし、indexも1にします。
最後の画像じゃない場合の処理は同じです。
【メインの処理】「前へ」が押された場合
これと同じ要領で「前へ」が押された場合の処理も考えて翻訳しコードを書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
window.onload = function () { let transVal = 0; index = 1; const $listItem = $('.js-carousel-item'),//画像 $length = $listItem.length;//画像の枚数 $('.js-carousel-next').on('click', function() { if(index == $length){ transVal = 0; index = 1; $('.js-carousel-list').css( 'transform', 'translateX('+transVal+'px)' ); }else{ index = index + 1; transVal = transVal - 600; $('.js-carousel-list').css( 'transform', 'translateX('+transVal+'px)' ); } }); //今回追加したエリア-前へが押された場合 $('.js-carousel-prev').on('click', function() { if(index == 1){ transVal = ($length - 1) * -600; index = 5; $('.js-carousel-list').css( 'transform', 'translateX('+transVal+'px)' ); }else{ index = index - 1; transVal = transVal + 600; $('.js-carousel-list').css( 'transform', 'translateX('+transVal+'px)' ); } }); } |
これでメインの処理は完成です。
次はナビバーの部分の処理を作りましょう。
サブの処理。ナビバーの作り方
画像が全部で何枚存在し、そのうちの何番目が表示されているのかを表すナビバーですが、indexも現在の画像が何番目なのかを把握するために使っているのでこれを流用すれば作れそうですね。
動きの仕組みは要素の横幅を%で変化させます。
今回の画像の枚数は5枚ですのでバーの幅を1/5%づつ増やすことで実装できます。
今回もcssの値を変更するので$(‘~’).css();を使用します。
1 2 3 4 5 |
indexNavVal = index/$length * 100; $('.js-carousel__index-item').css( 'width', indexNavVal+'%' ); |
これを適切な場所へ入れます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
window.onload = function () { let transVal = 0; index = 1; indexNavVal = 0; const $listItem = $('.js-carousel-item'),//画像 $length = $listItem.length;//画像の枚数 //今回追加したナビの処理 indexNavVal = index/$length * 100; $('.js-carousel__index-item').css( 'width', indexNavVal+'%' ); $('.js-carousel-next').on('click', function() { if(index == $length){ transVal = 0; index = 1; $('.js-carousel-list').css( 'transform', 'translateX('+transVal+'px)' ); }else{ index = index + 1; transVal = transVal - 600; $('.js-carousel-list').css( 'transform', 'translateX('+transVal+'px)' ); } //今回追加したナビの処理 indexNavVal = index/$length * 100; $('.js-carousel__index-item').css( 'width', indexNavVal+'%' ); }); $('.js-carousel-prev').on('click', function() { if(index == 1){ transVal = ($length - 1) * -600; index = 5; $('.js-carousel-list').css( 'transform', 'translateX('+transVal+'px)' ); }else{ index = index - 1; transVal = transVal + 600; $('.js-carousel-list').css( 'transform', 'translateX('+transVal+'px)' ); } //今回追加したナビの処理 indexNavVal = index/$length * 100; $('.js-carousel__index-item').css( 'width', indexNavVal+'%' ); }); } |
入れる箇所は3箇所あります
- サイトアクセス時に画像1がされているので、ボタンを押す処理の前に入れます
- 次へボタンを押し、スライド処理が終わった後に入れます
- 前へボタンを押し、スライド処理が終わった後に入れます
これでスライダーが完成です!!
コードをブラッシュアップしよう
このままでもスライダーは機能しますが、コードをブラッシュアップしてのちの変更などに対応できる保守性の高いコードにしましょう。
ポイントは2つ
- DOMアクセスは変数で管理
- 複数回使用される処理は関数にまとめる
DOMアクセスは変数で管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
window.onload = function () { let transVal = 0; index = 1; indexNavVal = 0; const $listItem = $('.js-carousel-item'),//画像 $length = $listItem.length,//画像の枚数 $indexItem = $('.js-carousel__index-item'),//indexナビ $carouselList = $('.js-carousel-list'),//画像リスト $nextBtn = $('.js-carousel-next'),//次へ $prevBtn = $('.js-carousel-prev');//前へ indexNavVal = index/$length * 100; $indexItem.css( 'width', indexNavVal+'%' ); $nextBtn.on('click', function() { if(index == $length){ transVal = 0; index = 1; $carouselList.css( 'transform', 'translateX('+transVal+'px)' ); }else{ index = index + 1; transVal = transVal - 600; $carouselList.css( 'transform', 'translateX('+transVal+'px)' ); } indexNavVal = index/$length * 100; $indexItem.css( 'width', indexNavVal+'%' ); }); $prevBtn.on('click', function() { if(index == 1){ transVal = ($length - 1) * -600; index = 5; $carouselList.css( 'transform', 'translateX('+transVal+'px)' ); }else{ index = index - 1; transVal = transVal + 600; $carouselList.css( 'transform', 'translateX('+transVal+'px)' ); }; indexNavVal = index/$length * 100; $indexItem.css( 'width', indexNavVal+'%' ); }); } |
複数使用される処理は関数にまとめる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
window.onload = function () { let transVal = 0; index = 1; indexNavVal = 0; const $listItem = $('.js-carousel-item'),//画像 $length = $listItem.length,//画像の枚数 $indexItem = $('.js-carousel__index-item'),//indexナビ $carouselList = $('.js-carousel-list'),//画像リスト $nextBtn = $('.js-carousel-next'),//次へ $prevBtn = $('.js-carousel-prev');//前へ indexNavVal = index/$length * 100; indexNav($indexItem,indexNavVal); $nextBtn.on('click', function() { if(index == $length){ transVal = 0; index = 1; transform($carouselList,transVal); }else{ index = index + 1; transVal = transVal - 600; transform($carouselList,transVal); } indexNavVal = index/$length * 100; indexNav($indexItem,indexNavVal) }); $prevBtn.on('click', function() { if(index == 1){ transVal = ($length - 1) * -600; index = 5; transform($carouselList,transVal); }else{ index = index - 1; transVal = transVal + 600; transform($carouselList,transVal); }; indexNavVal = index/$length * 100; indexNav($indexItem,indexNavVal) }); } function transform(carouselList,transVal){ carouselList.css( 'transform', 'translateX('+transVal+'px)' ); }; function indexNav(indexItem,indexNavVal){ indexItem.css( 'width', indexNavVal+'%' ); } |
まとめ
仕組み
画像横並びにした画像を用意します。
その画像1枚分と同じ大きさの画像を見せたいエリアを用意します。
表示させたいエリアにぶち込みます。
画像を表示させたいエリア以外では画像を表示させたくないので、overflow:hidden;ではみ出たエリアを非表示にします。
あとは横並びにした画像群をtransletで動かしてしまえば画像がスライドして現れているように見えます。
処理の流れ
↓
比較には現在表示している画像が何枚目なのかを知る必要があるので変数を用意し、画像がスライドする毎に変数の値を更新する
そして最後の画像が何枚目なのかを知る必要もあるので、画像全部の枚数を取得する
↓
- DOMアクセスは変数で管理
- 複数回使用される処理は関数にまとめる
次のステップ
お次はスライダーを自動再生してみましょう。
そして、現在はボタンを連打するとスライドの途中であっても次のスライドへ移動してしまうのでスライド中はボタンを無効にしてみましょう。
次のページ…準備中…
コメント