anime.jsのgridオプションを見ていて、NivoSliderのことを思い出しました。
ADs
派手なアニメーションが特徴のスライダー(カルーセル)です。jQueryプラグインとして動作します。
最近使っているサイトを見かけなくなったなと思って調べてみると、長年アップデートもされておらず公式サイトも行方不明になってしまったようで、リポジトリは残っているものの過去のものと言ってもいいような状況でした。
大げさなアニメーションは流行ではないかもしれませんが好きな人は好きだろうし使いどころもあるだろう、と思いanime.js(とjQuery)を使って作ってみました。
divをタイル状に並べ、backgroundに画像を指定して1枚の画像のように見せています。
その1個ずつのdivをアニメーションさせながら消したり動かしたりすることでインパクトのあるアニメーションを実装しています。
確かNivoSliderも同じ仕組みです。
HTMLはできるだけシンプルにしていじくり倒すのはjQueryに任せます。
div.sliderがスライダーの親要素となり、使用する画像には.slider-imgというクラスをつけます。
data-anime属性はアニメーションの種類を指定するオプションです(JSで定義します)。
1 2 3 4 5 6 |
<div class="slider"> <div data-anime="0"><img src="slide1.jpg" class="slider-img" alt="" /></div> <div data-anime="1"><img src="slide2.jpg" class="slider-img" alt="" /></div> <div data-anime="2"><img src="slide3.jpg" class="slider-img" alt="" /></div> <div data-anime="3"><img src="grid.jpg" class="slider-img" alt="" /></div> </div> |
div.sliderのwidthとheightがそのままスライダーの大きさになります。
pxでもいいですし、100vw/100vhと指定すればウインドウ全面をスライドショーとすることができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* 親要素(div.slider)の幅と高さでサイズを決める */ .slider { width: 100vw; height: 100vh; position: relative; overflow: hidden; } /* 以下は必須 */ .slider > div { width: 100%; height: 100%; display: flex; flex-wrap: wrap; position: absolute; left: 0; top: 0; } .slider > div > div { flex: none; background-repeat: no-repeat; } .slider > div img.slider-img { display: none; } |
まずはjQueryとanime.jsを読み込みます。
1 2 |
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/animejs@3.0.1/lib/anime.min.js"></script> |
次にスクリプト部分を書いていきます。
jQuery3系を使う場合、以下のスクリプトは</body>直前に書くように(つまり<head>には書かない)ようにしてください。
インターバルや分割数を指定します。
分割数は極端に多すぎるとさすがにしんどい(splitX * splitY個分divが生成される)のでほどほどにしておいたほうがいいと思います。
1 2 3 4 |
var interval = 2000; //スライド実行のインターバル var $slider = $('.slider'); //スライドの親要素 var splitX = 11; //X方向の分割数 var splitY = 5; //Y方向の分割数 |
スライド直下のdiv内部にdivを敷き詰めます。
これにbackgroundをずらしながら指定することで1枚の画像のように見せます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
var setDiv = function(){ $slider.each(function(key,value){ $(value).children().each(function(key2,value2){ var $div = $('<div />').css({ width: 100 / splitX + '%', height: 100 / splitY + '%', }); var i = 0; while(i < splitX * splitY){ $(value2).append($div.clone()); i++; } }); }); } |
ここが一番しんどかった…。
要は background-size: cover; background-position: center center; のように表示させることを目的としていますが、どんなサイズの画像であってもど真ん中に配置かつ余白ができないように拡大縮小してタイル状のdivに設定するということをやっています。
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 |
var setBg = function(sliderW,sliderH){ $slider.each(function(key,value){ $(value).children().each(function(key2,value2){ //value2 = slider > div var $img = $(this).find('.slider-img'); var imgW = $img.get(0).naturalWidth; var imgH = $img.get(0).naturalHeight; var imgSrc = $img.attr('src'); var fixY = 0; var fixX = 0; if(sliderW / sliderH < imgW / imgH){ //枠に比べて画像が横長の場合、高さをあわせる var bgs = 'auto ' + sliderH + 'px'; //ど真ん中に合わせるようにXを調整 var fixX = ((sliderH / imgH * imgW) - sliderW) / 2; } else { //枠に比べて画像が縦長の場合、幅をあわせる var bgs = sliderW + 'px auto'; //ど真ん中に合わせるようにYを調整 var fixY = ((sliderW / imgW * imgH) - sliderH) / 2; } $(value2).children('div').each(function(key3,value3){ //value3 = slider > div > div var bgpX = key3 % splitX / splitX ; var bgpY = Math.floor(key3 / splitX) / splitY; $(value3).css({ width: 100 / splitX + '%', height: 100 / splitY + '%', backgroundImage: 'url(' + imgSrc + ')', backgroundPosition: ((-1 * bgpX * sliderW) - fixX) + 'px ' + ((-1 * bgpY * sliderH) - fixY) + 'px', backgroundSize: bgs }); }); }); }); } |
NivoSliderでも何種類かアニメーションのパターンがありましたので、何パターンか定義してdata-anime属性で使い分けるようにしました。
とりあえず4種類ですが、anime.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 |
var animePattern = { 0: { scaleY: [1,0], easing: 'easeOutExpo', delay: anime.stagger(50,{ grid: [splitX,splitY], from: 'center', easing: 'linear', start: interval }) }, 1: { scale: [1,0], rotate: [0,360], easing: 'easeOutExpo', delay: anime.stagger(50,{ grid: [splitX,splitY], from: 'center', easing: 'linear', start: interval }) }, 2: { scaleY: [1,0], easing: 'easeOutExpo', delay: anime.stagger(50,{ grid: [splitX,splitY], from: 'first', axis: 'y', easing: 'linear', start: interval }) }, 3: { scaleX: [1,0], easing: 'easeOutExpo', delay: anime.stagger(50,{ grid: [splitX,splitY], from: 'first', axis: 'x', easing: 'linear', start: interval }) } }; |
前述のアニメーションパターンに共通の設定(targetsやcomplete)を追加し、アニメーション関数を完成させます。
要は連想配列の足し算です。
1 2 3 4 5 6 7 8 9 10 11 12 |
var animation = function(){ var param = animePattern[$slider.find('> div:last-child').attr('data-anime')]; param['targets'] = $slider.find('> div:last-child > div').get(); param['complete'] = function(el){ $slider.find('> div:last-child').prependTo($slider); $slider.find('> div:first-child > div').css({ transform: '' }); animation(); }; anime(param); } |
最後に実行します。
resize時に背景指定関数を実行することで、ウインドウをリサイズしてもズレないようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 |
//divを敷き詰める setDiv(); //背景の設定とアニメーション実行 $(window).on('load',function(){ setBg($slider.width(),$slider.height()); animation(); }); //リサイズ時に背景を取り直す $(window).on('resize',function(){ setBg($slider.width(),$slider.height()); }); |
ソース全文はDEMOをご参照ください。
ADs
コメントはまだありません。