よくある画像スライダーですが、先日、ズームインしながらフェードで切り変わるという少し特殊なスライダーを実装する必要があったのでその時の備忘録として。
スライダー系のプラグインは様々ありますが、プラグインを使用して実現する方法がパッと浮かばなかったので、1から自分でスクリプトを組みました。
と言いっても、スクリプトの処理自体はタイミングを合わせてクラスを付け外しするだけのシンプルもので、アニメーション部分はCSSに任せてあります。
また、jQueryは使わずに実装してみました。
動作デモ
まずは完成したスライダーの実物を載せておきます。
See the Pen ズームインしながらフェードで切り替わるスライダー by ddryo (@ddryo-the-encoder) on CodePen.
スクリプトとそれに対応するHTML・CSS
まず、HTML側はスライダーの親要素に slide_wrapp
という名前のIDがついているとし、スライダーとして機能する要素に slide_item
という名前のクラスがついているとします。
HTML
<ul id="slide_wrapp">
<li class="slide_item"><!-- スライド1の中身 --></li>
<li class="slide_item"><!-- スライド2の中身 --></li>
<li class="slide_item"><!-- スライド3の中身 --></li>
</ul>
表示したい内容をliタグに突っ込んでください。
次いで、スクリプトです。
処理の内容としては、スライド要素.slide_item
に対して、順番にshow_
とzoom_
という2種類のクラスを付け外していくだけのものです。
JS
window.addEventListener('load', function () {
sliderStart();
});
function sliderStart() {
const slide = document.getElementById('slide_wrapp'); //スライダー親
const slideItem = slide.querySelectorAll('.slide_item'); //スライド要素
const totalNum = slideItem.length - 1; //スライドの枚数を取得
const FadeTime = 2000; //フェードインの時間
const IntarvalTime = 5000; //クロスフェードさせるまでの間隔
let actNum = 0; //現在アクティブな番号
let nowSlide; //現在表示中のスライド
let NextSlide; //次に表示するスライド
// スライドの1枚目をフェードイン
slideItem[0].classList.add('show_', 'zoom_');
// 処理を繰り返す
setInterval(() => {
if (actNum < totalNum) {
let nowSlide = slideItem[actNum];
let NextSlide = slideItem[++actNum];
//.show_削除でフェードアウト
nowSlide.classList.remove('show_');
// と同時に、次のスライドがズームしながらフェードインする
NextSlide.classList.add('show_', 'zoom_');
//フェードアウト完了後、.zoom_削除
setTimeout(() => {
nowSlide.classList.remove('zoom_');
}, FadeTime);
} else {
let nowSlide = slideItem[actNum];
let NextSlide = slideItem[actNum = 0];
//.show_削除でフェードアウト
nowSlide.classList.remove('show_');
// と同時に、次のスライドがズームしながらフェードインする
NextSlide.classList.add('show_', 'zoom_');
//フェードアウト完了後、.zoom_削除
setTimeout(() => {
nowSlide.classList.remove('zoom_');
}, FadeTime);
};
}, IntarvalTime);
}
*上記のコードはES2015の記法を用いています。
コピペする際はBabelなどでES5へトランスパイルしてお使いください。
slideStart()
を呼び出せばスライダーが開始します。上記ではwindowのloadイベントで呼び出していますが、どのタイミングで呼び出すべきかについては後述します。
最後に、CSSでズームとフェードの各アニメーションを担当します。
先ほどのスクリプトで指定したFadeTime
とIntarvalTime
に秒数合わせて transitionプロパティ を指定するので注意して下さい。
CSS(下のコードはSCSS)
#slide_wrapp{
position: relative;
overflow: hidden;
.slide_item{
opacity: 0;
transform: scale(1);
transition: opacity 2s linear, transform 7.5s linear; //秒数に注意
position: relative;
z-index: 1;
&:not(:first-child){
position: absolute;
top: 0;
left : 0;
}
&.show_{
opacity: 1;
}
&.zoom_{
transform: scale(1.1);
}
img{
display: block; //下に余白ができないように
}
}
}
フェードに対応する opacityプロパティ に対するトランジションの長さはFadeTime
と同じ時間(ここでは2秒)にし、ズームに対応する transformプロパティ に対するトランジションの長さは、最低でもFadeTime
とIntarvalTime
を合わせた秒数(ここでは計7秒)にしてください。
上記では余裕を持って + 0.5秒 の 7.5秒 を指定しています。
スライダーを開始するタイミングについて
先に示したコードでは、windowのloadイベントで呼び出しています。
この場合、スライダー機能自体になんら影響はありませんが、サイトの読み込み速度が遅い場合はスライダーの表示がその分遅れてしまいます。
DOM読み込み時に呼び出しても大丈夫ですが、1枚目の読み込みに時間がかかる場合、その初回表示のみ表示時間が短くなります。
また、初回のみ、ズームがうまく動作しないことがあります。
DOM読み込み時に呼び出す場合
//これだと初回動作が安定しない
document.addEventListener('DOMContentLoaded', function () {
sliderStart();
});
そこで、一番良いのはスライダーの1枚目を読み込んだ時点でスライダーを開始することです。
スライダーの中身が画像だけの場合はこのタイミングがベストでしょう。
imgタグのonloadイベント属性を使います。
1枚目のスライダー画像の読み込み時に呼び出す
<ul id="slide_wrapp">
<li class="slide_item"><img src="image.jpg" alt="画像" onload="sliderStart()"></li>
<!-- その他のスライド... -->
</ul>
動作デモのCodePenでもこのタイミングで呼び出していますので、参考にしてみて下さい。
コメント
コメント一覧 (9件)
スライダーを調べていて、たどり着きました!
コチラのサイトのスライダー、メチャクチャカッコいいのですが、どのようにやっているのでしょうか?
プラグイン一発でできるのでしょうか?
お時間のある時に教えていただけましたら嬉しいです。(^^)
よろしくお願いします!
swiper.jsというプラグインでできますよー!
これ、ドンピシャでやりたかったことでした。
解説もコードも分かりやすくて非常に参考になりました。ありがとうございます。
検索して辿り着きました。とても良いコードを公開して頂きありがとうございます。
テスト設置させて頂き、希望通りの動きでとても満足しています。
ただ、Windows 7 の IE11 にて動作しませんでした。
IE11 のエラーを確認すると、JavaScript にて16行目「setInterval(() => {」が「構文エラー」と表示されています。
html ファイルでは1枚目の画像で指定している「onload=”sliderStart()”」が「定義されていません」とエラーが出ています。
今更、Windows 7 の IE11 ですがもし対策がわかれば幸いです。
この記事で書いているコードはES2015の記法なので、実際にサーバーへアップロードする際はES5の記述に戻してお使いください。(Babelなどを使うと楽です)
了様
早速のアドバイスを有りがとうございます。
babelwを使って変換してみます。
了様
Babelオフィシャルサイト
https://babeljs.io/repl/
にて、ES5に変換して Windows 7 IE11 で動作するのを確認しました。
ありがとうございます。
よかったです!
この動きに近いスライダーを探してました!詳しい解説までしてありがとうございます。
一点ご教示頂きたいのですが、1ページに複数箇所に設置する場合は、
「document.getElementById」部分の親部分IDではなくclassになると思うので変更が必要と思うのですが、
どのような変更すると良いのでしょうか?
変更部分が間違っていたらスミマセン
宜しくお願いします。