slick.jsを使って横幅いっぱい+前後の画像を半透明にしたスライドを実装しようとしたのですが、きれいに動作させようとすると結構手間がかかってしまいました。
slick.js本体の修正やコールバック関数を使うことでいい感じに実装できましたのでよかったら参考にしてみてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
※以下のHTMLの「slider_inner」に対してslick()を実行しています。 <script type="text/javascript"> $(function(){ $('.slide_inner').slick({ dots: true, autoplay: true, pauseOnFocus: false, pauseOnHover: false }); }); </script> <div class="slide"> <div class="slide_inner"> <div><img src="https://placehold.jp/443388/ffffff/1000x300.png?text=1枚目" alt="" /></div> <div><img src="https://placehold.jp/448833/ffffff/1000x300.png?text=2枚目" alt="" /></div> <div><img src="https://placehold.jp/883344/ffffff/1000x300.png?text=3枚目" alt="" /></div> <div><img src="https://placehold.jp/334444/ffffff/1000x300.png?text=4枚目" alt="" /></div> </div> </div> |
ADs
slick.jsは子要素を横並びにし、親要素をoverflow:hiddenにして要素の幅ずつ移動させることでアニメーションを実装しています。
簡略化すると、以下のようなHTMLになっています。
1 2 3 4 5 6 7 |
<div class="slide_inner slick-slider"> <div aria-live="polite" class="slick-list"><!-- これがoverflow:hiddenになっている --> <div class="slick-slide">これがスライド</div> <div class="slick-slide">これがスライド</div> <div class="slick-slide">これがスライド</div> </div> </div> |
この「slick-list」がoverflow:hiddenなので、これをvisibleにすれば横幅いっぱいにできそうです。
それだけだと横スクロールが出てしまいますので、スライドの親要素をoverflow:hiddenにします。
1 2 3 4 5 6 7 8 |
<div class="slide" style="overflow: hidden"> <div class="slide_inner"> <div><img src="https://placehold.jp/443388/ffffff/1000x300.png?text=1枚目" alt="" /></div> <div><img src="https://placehold.jp/448833/ffffff/1000x300.png?text=2枚目" alt="" /></div> <div><img src="https://placehold.jp/883344/ffffff/1000x300.png?text=3枚目" alt="" /></div> <div><img src="https://placehold.jp/334444/ffffff/1000x300.png?text=4枚目" alt="" /></div> </div> </div> |
うまくいってそうですが、一周したあとの1枚目と2枚目、逆方向(右側)へ動いたときの4枚目と3枚目が途切れてしまいます。
slick.jsでは無限ループを実現するために前後に要素を複製して挿入しているのですが、この要素が1枚ずつしかないことが原因です。
開発者ツールで見ると分かりやすいですが、「slick-cloned」というクラスが複製された要素です。
複製する要素を1枚多くすればこの問題は解決します。
コールバックやCSSでは解消できなかったので、slick.js本体を編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//1079行目あたり、cloneする枚数が増えた分初期位置がずれるので調整する(スライド2枚分ずらす) //cloneが2枚になったのでその幅分初期値をずらす //_.slideOffset = (_.slideWidth * _.options.slidesToShow) * -1; _.slideOffset = (_.slideWidth * _.options.slidesToShow) * -2; //2300行目あたり、infiniteCount - 1にする for (i = _.slideCount; i > (_.slideCount - //cloneする枚数を1枚多くする //infiniteCount); i -= 1) { infiniteCount - 1); i -= 1) { //2310行目あたり、infiniteCount + 1にする //cloneする枚数を1枚多くする //for (i = 0; i < infiniteCount; i += 1) { for (i = 0; i < infiniteCount + 1; i += 1) { |
これで途切れることのない無限ループするスライドが実装できました。
次に、前後の要素を半透明にしてみましょう。
アクティブな要素には「slick-current」と「slick-active」というクラスが付加されますので、以下のCSSを書けばそれでよさそうです。
1 2 3 4 5 6 7 |
.slide .slick-slide { opacity: 0.5; transition: 0.5s; } .slide .slick-current { opacity: 1; } |
しかし実際に見てみると、最後から1枚目、1枚目から最後へ動いたときにtransitionが効いていません。
これは複製された要素に対して「slick-current」と「slick-active」クラスが付加されないことが原因です。
あとaddClass/removeClassのタイミングもちょっとおかしいような?
そこで複製された要素へもクラスを付加しつつ、いい感じのタイミングでクラスの付け外しを行う処理を自力で書きます。
※「slick-now」というクラスをアクティブなスライドに追加する場合の例です
1 2 3 4 5 6 7 |
.slide .slick-slide { opacity: 0.5; transition: 0.5s; } .slide .slick-now { opacity: 1; } |
slick.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 |
$(function(){ var $slide = $('.slide_inner'); var slideNum = $('.slide_inner').children().length; //アニメーション開始前にクラスを外す $slide.on('beforeChange', function(event, slick, currentSlide, nextSlide){ $(this).find('.slick-slide').removeClass('slick-now'); }); //アニメーション完了後、アクティブな要素+その要素が複製された要素にクラスを付加 //「data-slick-index」属性で連番が振られるのでそれを利用する $slide.on('afterChange', function(event, slick, currentSlide, nextSlide){ $(this) .find('.slick-slide[data-slick-index="' + currentSlide + '"]') .add('.slick-slide[data-slick-index="' + (slideNum - currentSlide) + '"]') .add('.slick-slide[data-slick-index="' + (slideNum + currentSlide) + '"]') .addClass('slick-now'); }); //初回のみ、1枚目の要素にクラスを付加 $slide.on('init',function(){ $(this).find('.slick-current').addClass('slick-now'); }); //スライドを実行する $slide.slick({ dots: true, autoplay: true, pauseOnFocus: false, pauseOnHover: false }); }); |
レスポンシブにする場合、固定幅を解除しつつスライド要素が幅100%で収まるように調整すれば横幅いっぱいのスライドになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@media only screen and (max-width: 500px){ body { min-width: 0; } .slide_inner { width: auto; } .slide_inner img { width: 100%; height: auto; } } |
アクティブな要素+その要素が複製された要素をカレントとして扱っているため、すごく横長なモニターや縮小されて表示されると半透明でない要素が2枚できています…。
スライドの枚数を多めにするか、極端な環境は見ないことにしましょう…。
横幅いっぱい+前後半透明のカルーセル、というのはよく見かける動きですが、slick.jsを使うとちょっとめんどくさいですね…。ほかにおすすめのプラグインがあれば教えてください_(._.)_
以前の記事でslick.jsと同じぐらい有名でよく使われているbxSliderを使った場合のカスタマイズを紹介しています。
bxSlider派の方は参考にしてみてください。
ADs
こんにちは。
前後の画像を透過するコードを参考にさせていただきました。
ただ問題が起きまして、画像を増やした際に、途中で両側の透過が適用されなくなるタイミングがあります…
jsがさっぱりでどこの記述が影響しているのか分からず…
ご教授いただけますと助かります。