前提
カンタンにスライドショー(スライダー,カルーセル)を実装できる人気のjQueryプラグインslick。
slick日本語翻訳ドキュメントのresponsiveページにもある通り、responsiveのオプションにブレイクポイントを書いておけば、画面幅に合わせて様々な設定ができます。
...ですが、このresponsiveの中に書いた内容は、もし同一ページでページリロードした時にデフォに設定したものが適用されてしまい、responsiveで書いた設定が適用されず、表示が崩れる事象に遭遇しました。
今回はその解決策を考えてみました。
変更前の状態を確認
やりたいこととしては、以下のような挙動を目指していました。
- PC表示の際はスライダーアイテムを3枚表示させて、1枚ずつ自動で入れ替える
- SP(769px以下)表示の際はスライダーアイテムを1枚だけ表示させて、1枚ずつ自動で入れ替える
$('.sliderList').slick({
dots: true,
infinite: true,
autoplay: true,
autoplaySpeed: 2000,
speed: 300,
slidesToShow: 3,
slidesToScroll: 1,
responsive: [
{
breakpoint: 769,
settings: {
slidesToShow: 1,
slidesToScroll: 1
}
}
]
});
これでも一見してきちんと動いているようになるのですが…
これだとデベロッパーツールでSPの画面幅にした時に、画面幅を選択した最初はresponsiveに設定した通り、正しく1枚になるのですが、その状態でページリロードするとPCの時の3枚表示になってしまってレイアウトが崩れました。
修正案
一度slick()の設定を実行してしまっていると、ページリロードされた際に新しくslick()が動かないことが原因でした。
こうした問題に備えて、slickではunslickという機能が用意されているので、これを使います。
流れとしては以下の通りです。
- initializeSlick()関数を作り、その中でウィンドウの幅をチェック。ウインドウ幅に応じて三項演算子で1か3を付与。
- ウインドウ幅に応じてslick()でスライダーの見た目の挙動を設定。 さっきの三項演算子で変数slidesToShowに入れた値をslick()のオブジェクト内のキーslideToShowの値に設定
- ウィンドウのリサイズされたかどうか監視させるため$(window).on('resize', function() {});を記述して、ここで画面幅に応じてHTMLのslick機能を削除したりする
そして、実際のコードは以下のようにしました。
function initializeSlick() {
var windowWidth = $(window).width();
var slidesToShow = (windowWidth < 769) ? 1 : 3;
$('.multiple-items').slick({
dots: true,
infinite: true,
autoplay: true,
autoplaySpeed: 2000,
speed: 300,
slidesToShow: slidesToShow,
slidesToScroll: 1
});
}
initializeSlick();
$(window).on('resize', function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
var windowWidth = $(window).width();
if (windowWidth < 769) {
$('.multiple-items').slick('unslick');
} else {
initializeSlick();
}
}, 250);
});
ウィンドウのリサイズされたかどうか監視部分は、何をやっているのか
以下の部分がちょっとややこしいので詳しくみていきます。
$(window).on('resize', function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
var windowWidth = $(window).width();
if (windowWidth < 769) {
$('.multiple-items').slick('unslick');
} else {
initializeSlick();
}
}, 250);
});
clearTimeout(resizeTimer)
は、setTimeout()
関数によって設定された遅延実行のタイマーをクリアさせるためにあります。
resizeTimer
は、ウィンドウのリサイズイベントが連続して発生する場合に、前回のタイマーをクリアして新たなタイマーを設定するために使用されています。連続してリサイズイベントが発生しても、最後のリサイズイベントから一定時間経過してから処理が実行されるようになります。
まとめると動作の流れは次のようになります:
- ウィンドウのリサイズイベントが発生。
-
clearTimeout(resizeTimer)
によって、もし存在していれば前回のタイマーがクリア。 -
setTimeout()
関数によって新たなタイマーが設定。250ミリ秒後に処理が実行されるように設定しています。 - 250ミリ秒間、連続したリサイズイベントが発生しない場合、指定した処理が実行されます。この場合、ウィンドウの幅をチェックし、条件に応じてSlickを初期化または解除します。
つまり、clearTimeout(resizeTimer)
は、連続してリサイズイベントが発生しても最後のリサイズイベントから一定時間が経過するまで待ち、処理が実行されるのを遅延させる役割を果たしています。
その次のif文ですが、ここではブレイクポイントの幅を条件式に指定しています。
if (windowWidth < 769) {
$('.multiple-items').slick('unslick');
} else {
initializeSlick();
}
今回はSPの769pxをブレイクポイントにしているので、この幅の時に一度slick('unslick')
をすると、HTMLに設定したスライドやカルーセルの動作、ドットナビゲーション、自動再生などの機能を一時的に無効化させています。
あとは、最初に設定したinitializeSlick();が動いて、通常のresponsiveの設定が適用されるという仕組みです。
# 感想
今回はブレイクポイントが2パターンなので三項演算子でどうにかしましたが、ブレイクポイントが増えた時など、改善の余地がありそうです。
これでいいのか謎ですが、一旦これしか思いつかないのでこんな感じにしていますが、何か不足やもっと良い方法があれば、ぜひ教えてください。