すぐに使える!jQueryを使用してウインドウ幅一杯にメインビジュアル用のスライダーの実装工程を学ぶ!jQuery Lab第1回
- カテゴリー jQuery Lab連載記事
2012年12月から雑誌Web Designingの『jQuery Lab.』にて連載をさせて頂くことになりました。ここではjQueryを使ったチュートリアルやプラグインの紹介をさせていただく予定です。
当ブログでは、紙面の関係で載りきらなかった部分やサンプルのより細かい解説をしていきたいと思います。
12月号のテーマは、
「jQueryを使用してウインドウ幅一杯にメインビジュアル用のスライダーを実装する」
になります。
第一回サンプルの解説
多機能なコンテンツスライダーは既に多数リリースされていますが、プラグインは様々な場面を想定して作られているため、実際には使っていない機能までたくさんあります。
そこで今回は、VOGUEのようにメインビジュアルに特化したコンテンツスライダーの実装方法を作成してみたいと思います。
jQuery Lab 第1回で作成したサンプル
今回作成するサンプルはこちらです。
http://www.html5-memo.com/sample/jq01/
メインの画像が中央に、その両側には前後のグラフィック画像に黒い半透明の画像が被さった状態で表示されるスライダーです。
前後の画像が両側に表示されるため、ウィンドウサイズが変わっても横幅いっぱいに画像が表示され、よりグラフィカルなイメージを与えることができます。
また、カスタマイズとしてボタンでの操作の他に一定時間でアニメーションさせる機能や、ページをスクロールをさせて、グラフィックエリアが見えなくなったタイミングでヘッダーのグローバルナビゲーションの固定も実装したいと思います。
実装の流れ
実装の大まかな流れを解説します。
すべてのコメントはページ下部の「サンプルコード」にありますので、そちらもご覧下さい。
1:設定用変数の用意
まずは、オプションを管理する変数を用意します。
スライドの速度・イージング、自動スライドの有無・インターバルを簡単に変更出来るよう、スクリプトの最初で変数を定義します。
var options = { duration: 400, easing: 'easeOutCubic', auto: false, interval: 3000 };
2:HTMLの操作
次に、HTMLの操作を行っていきます。
li要素の先頭が、スライダー中央に来るようにli要素を並び替えます。
// 最初のli要素を中心にするため、変数shiftの分liを入れ替えます。 // 入れ替えは、最後のliを最初に挿入することで実現しています。 for(var i = shift; i > 0; i--) $element.find('li').eq(len - i).remove().prependTo($element);
そして、誤クリックを防ぐための透明のdivをHTMLに加えます。
// <div class="layer">をulの後に2個挿入します。 for(var i = 0; i < 2; i++) $('<div class="layer"></div>').insertAfter($element); // 上記で挿入した<div class="layer">を変数に入れます。 $leftlayer = $container.find('.layer').eq(0); $rightlayer = $container.find('.layer').eq(1);
3:初期表示の設定
次に画像を中央に配置するための関数を作成します。
ウィンドウの幅からli要素の幅を引いて半分にした値を、ulに設定すれば中央に表示されます。
ただし、そのままではulの左側に空白が出来てしまいますので、先ほどの値からli要素2つ分の幅を引きます。
※この時、li要素2つ分の幅を引いているため、「HTMLの操作」の際にli要素を2回並べ替えています。
// windowの幅からlistの幅を引いたものを半分にします。 // そこから、liの幅に変数shiftを掛けたもの引きます。 var _val = ($window.width() - lw) / 2 - lw * shift; // ulのwidthに、liの幅にliの個数を掛けたものを設定して、liを横並びにします。 // ulのleftに、_valを設定して画像が中央に表示されるようにします。 $element.css({ 'width': lw * len, 'left': _val });
また、先ほどの値をもとに透明のdivを中央画像の左右に配置します。
// $leftlayerのleftに、変数_valにliの幅を足し設定します。 // これにより、透明のdivが中央のliの左隣に重なり誤クリックを防ぎます。 $leftlayer.css('left', _val + lw); // $rightlayerのleftに、変数_valにliの幅に3を掛けた値を足し設定します。 // これにより、透明のdivが中央のliの右隣に重なり誤クリックを防ぎます。 $rightlayer.css('left', _val + lw * 3);
4:アニメーションの仕組みを作成
次に、アニメーションを管理する関数を作成します。
この関数では、自動スライドの停止・アニメーション・コールバック関数の呼び出しを行っています。この際、引数に入れた値によって右に動くか左に動くかを調整できるようにすることで、一つの関数で左右の動きを管理します。
function slide(direction){ // ulがアニメーション中なら、以降の処理を中断します。 if($element.filter(':animated').length) return; // 変数optionsのautoがtrueなら、自動スライドを中止します。 if(options.auto) clearInterval(timer); // 変数valに移動量をを入れます。 // 引数がtrueならliの幅分マイナスの値を、falseならliの幅分の値を入れます。 val = (direction)? -lw: lw; // animateメソッドを使い、ulをアニメーションさせます。 // アニメーション完了後に関数callbackを実行します。 $element.animate({ 'marginLeft': val }, options.duration, options.easing, callback); };
先ほどの関数から呼び出されたコールバック関数では、先ほどの関数で動かしたmargin-leftをリセットするとともに、一番端のli要素を逆端に回りこませてループを行っています。その後自動スライドの再開を行っています。
function callback(){ // 関数slideで定義した変数valが、0より小さければ最初のliを最後に移動させ、0より大きければ最後のliを最初に移動させる (0 > val)? $element.find('li').eq(0).remove().appendTo($element): $element.find('li').eq(len - 1).remove().prependTo($element); // 関数slideで、ulをanimateさせた時に付与されたmarginleftの値をリセットします。 $element.css('marginLeft', 0); // 変数optionsのautoがtrueなら、自動スライドを開始します。 if(options.auto) timer = setInterval(function(){ slide(true) }, options.interval); };
5:ヘッダー固定の仕組みを作成
次にヘッダーを固定する関数を作成していきます。
スクロールされるたびに、スクロール量とスライダーエリアの位置を比較します。
スクロール量がスライダーエリアの高さを越えた場合は、ヘッダーにposition:fixedを与え、越えない場合はヘッダーにposition:staticを設定します。
function scroll(){ // スクロール量がcontainerYを上回ったら、関数_fixedを実行します。 // スクロール量がcontainerYを上回ったら、関数_staticを実行します。 (containerY <= $window.scrollTop())? _fixed() : _static(); // $headerにfixedを設定し、画面上部に固定します。 // $headerをfixedにするとその分のheightが失われるので、$headerAfterにheaderY分のmarginを設定します。 function _fixed(){ $header.css({ 'position': 'fixed', 'top': 0, 'left': 0 }); $headerAfter.css('marginTop', headerY); }; // $headerにstaticを設定し、デフォルトの挙動に戻します。 // $headerをstaticにするとheightが戻るので、$headerAfterのmarginをリセットします。 function _static(){ $header.css({ 'position': 'static', 'top': '', 'left': '' }); $headerAfter.css('marginTop', ''); }; }; [/javascript] <img src="http://www.html5-memo.com/wp-content/uploads/2012/12/021.jpg" alt="ヘッダーを固定させるタイミング" title="ヘッダーを固定させるタイミング" width="574" height="926" class="alignnone size-full wp-image-5519" /> <h3>6:イベントの登録</h3> 最後にイベントの登録を行います。 まず、リサイズイベントに「初期表示」で作成した関数resizeを登録します。 次に、#nextと#prevのクリックイベントに「アニメーションの仕組みを作成」で作った関数slideを登録します。その際、#nextには引数としてtrueを#prevにはfalseを渡して登録します。 そしてスクロールイベントに「ヘッダー固定の仕組みを作成」で作った関数scrollを登録します。 以上で完成です。 [javascript font_size="90%"] // windowにresizeイベントを登録します。 // リサイズイベントが起きるたびに、関数resizeを実行します。 $window.on('resize', resize); // $nextにclickイベントを登録します。 // $nextをクリックしたら、関数sliderの引数にtrueを渡して実行します。 $next.on('click', function(){ slide(true); }); // $prevにclickイベントを登録します。 // $prevをクリックしたら、関数sliderの引数にtrueを渡して実行します。 $prev.on('click', function(){ slide(false); }); // windowにscrollイベントを登録します。 // スクロールイベントが起きるたびに、関数scrollを実行します。 $window.on('scroll', scroll);
サンプルコード
HTML
<div id="slider"> <ul class="clearfix"> <li><a href="#"><img src="img/01.jpg" alt="" width="900" height="600" /></a></li> <li><a href="#"><img src="img/02.jpg" alt="" width="900" height="600" /></a></li> <li><a href="#"><img src="img/03.jpg" alt="" width="900" height="600" /></a></li> <li><a href="#"><img src="img/04.jpg" alt="" width="900" height="600" /></a></li> <li><a href="#"><img src="img/05.jpg" alt="" width="900" height="600" /></a></li> <li><a href="#"><img src="img/06.jpg" alt="" width="900" height="600" /></a></li> </ul> <p id="prev"><img src="img/prev.png" alt="" width="64" height="64" class="rollover" /></p> <p id="next"><img src="img/next.png" alt="" width="64" height="64" class="rollover" /></p> <!-- /slider --></div> <div id="header"> <h1><span class="stage"><img src="img/logo.png" alt="" width="240" height="24" /></span></h1> <div id="nav"> <ul class="clearfix stage"> <li><a href="#">HOME</a></li> <li><a href="#">NEWS</a></li> <li><a href="#">ABOUT</a></li> <li><a href="#">RECRUIT</a></li> <li><a href="#">CONTACT</a></li> </ul> </div> <!-- /header --></div>
CSS
#slider{ position: relative; width:100%; height: 480px; overflow: hidden; background: url(../img/loading.gif) no-repeat center center; } #slider ul{ position: absolute; top: 0; left: 0; } #slider li{ float: left; } #slider #prev, #slider #next{ position: absolute; top:220px; cursor: pointer; } #slider #prev{ left:20px;} #slider #next{ right:20px;} /* for script */ #slider ul, #slider #next, #slider #prev{ visibility: hidden; } #slider .layer{ width: 900px; height: 480px; position: absolute; top: 0; left: 0; background: url(../img/dot.gif) repeat 0 0 #666; opacity: 0.5; filter: alpha(opacity=50); } /* * common */ .stage{ width: 980px; margin: 0 auto; } /* * header */ #header{ width: 100%; } #header h1{ padding: 10px 0; background: #fff; background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ccc)); background: -moz-linear-gradient(top, #fff 0%, #ccc); } #header h1 span{ display: block; } #header #nav{ background: #333; } #header #nav li{ float: left; } #header #nav a{ display: block; padding: 15px; text-decoration: none; color: #fff; font-family: normal Arial,Helvetica,sans-serif; } #header #nav a:hover{ color: #ccc; background: #000; }
JavaScript
(function(){
/*
* ! 変数optionを作成して初期設定します。
* duration: 写真の移動するスピードの設定
* easing: easing.jsのイージングの設定
* auto: 自動再生をするかしないかの設定(true/false)
* interval: 一枚の写真の静止する秒数の設定
*/
var options = {
duration: 400,
easing: ‘easeOutCubic’,
auto: false,
interval: 3000
};
/*
* ! DOMや数値などを変数に入れ、キャッシュさせます。
* $container:
* $list:
* $next:
* $prev:
* shift: $prevをクリック時に空白が出来ないよう移動させる枚数
* lw: $listの幅
* len: $listの個数
* timer: timer管理のための変数をあらかじめ用意
*/
var $window = $(window),
$container = $(‘#slider’),
$element = $container.find(‘ul’),
$list = $element.find(‘li’),
$next = $container.find(‘#next’),
$prev = $container.find(‘#prev’),
shift = 2,
lw = $list.width(),
len = $list.length,
timer = ”;
/*
* ! DOMや数値などを変数に入れ、キャッシュさせます。
* $header:
* headerY:
* containerY:
*/
var $header = $(‘#header’),
$headerAfter = $header.next(),
headerY = $header.height(),
containerY = $container.height();
/*
* ! 関数initializeを作成
* windowのロードが完了された時に実行する関数
*/
function initialize(){
// 関数setupを実行します
setup();
// windowにresizeイベントを登録します。
// リサイズイベントが起きるたびに、関数resizeを実行します。
$window.on(‘resize’, resize);
// $nextにclickイベントを登録します。
// $nextをクリックしたら、関数sliderの引数にtrueを渡して実行します。
$next.on(‘click’, function(){ slide(true); });
// $prevにclickイベントを登録します。
// $prevをクリックしたら、関数sliderの引数にtrueを渡して実行します。
$prev.on(‘click’, function(){ slide(false); });
// windowにscrollイベントを登録します。
// スクロールイベントが起きるたびに、関数scrollを実行します。
$window.on(‘scroll’, scroll);
// 関数loadを実行します。
load();
// 変数optionsのautoがtrueなら、関数sliderの引数にtrueを渡して一定間隔で実行します。
// 間隔は変数optionsのintervalに従います。
if(options.auto) timer = setInterval(function(){ slide(true) }, options.interval);
};
/*
* ! 関数setupを作成
* 初期表示を構築するための関数です。
*/
function setup(){
// 最初のli要素を中心にするため、変数shiftの分liを入れ替えます。
// 入れ替えは、最後のliを最初に挿入することで実現しています。
for(var i = shift; i > 0; i–) $element.find(‘li’).eq(len – i).remove().prependTo($element);
//
for(var i = 0; i < 2; i++) $('
‘).insertAfter($element);
// 上記で挿入した
$leftlayer = $container.find(‘.layer’).eq(0);
$rightlayer = $container.find(‘.layer’).eq(1);
// 関数resizeを実行します。
resize();
};
/*
* ! 関数resizeを作成
* windowがrisizeする度に実行する関数
*/
function resize(){
// windowの幅からlistの幅を引いたものを半分にします。
// そこから、liの幅に変数shiftを掛けたもの引きます。
var _val = ($window.width() – lw) / 2 – lw * shift;
// ulのwidthに、liの幅にliの個数を掛けたものを設定して、liを横並びにします。
// ulのleftに、_valを設定して画像が中央に表示されるようにします。
$element.css({
‘width’: lw * len,
‘left’: _val
});
// $leftlayerのleftに、変数_valにliの幅を足し設定します。
// これにより、透明のdivが中央のliの左隣に重なり誤クリックを防ぎます。
$leftlayer.css(‘left’, _val + lw);
// $rightlayerのleftに、変数_valにliの幅に3を掛けた値を足し設定します。
// これにより、透明のdivが中央のliの右隣に重なり誤クリックを防ぎます。
$rightlayer.css(‘left’, _val + lw * 3);
};
/*
* ! 関数slideを作成
* アニメーションを管理する関数
*/
function slide(direction){
// ulがアニメーション中なら、以降の処理を中断します。
if($element.filter(‘:animated’).length) return;
// 変数optionsのautoがtrueなら、自動スライドを中止します。
if(options.auto) clearInterval(timer);
// 変数valに移動量をを入れます。
// 引数がtrueならliの幅分マイナスの値を、falseならliの幅分の値を入れます。
val = (direction)? -lw: lw;
// animateメソッドを使い、ulをアニメーションさせます。
// アニメーション完了後に関数callbackを実行します。
$element.animate({
‘marginLeft’: val
}, options.duration, options.easing, callback);
};
/*
* ! 関数callbackを作成
* 関数slideのコールバック関数
*/
function callback(){
// 関数slideで定義した変数valが、0より小さければ最初のliを最後に移動させ、0より大きければ最後のliを最初に移動させる
(0 > val)? $element.find(‘li’).eq(0).remove().appendTo($element): $element.find(‘li’).eq(len – 1).remove().prependTo($element);
// 関数slideで、ulをanimateさせた時に付与されたmarginleftの値をリセットします。
$element.css(‘marginLeft’, 0);
// 変数optionsのautoがtrueなら、自動スライドを開始します。
if(options.auto) timer = setInterval(function(){ slide(true) }, options.interval);
};
/*
* ! 関数scrollを作成
* ヘッダーを固定するための関数
*/
function scroll(){
// スクロール量がcontainerYを上回ったら、関数_fixedを実行します。
// スクロール量がcontainerYを上回ったら、関数_staticを実行します。
(containerY <= $window.scrollTop())?
_fixed() :
_static();
// $headerにfixedを設定し、画面上部に固定します。
// $headerをfixedにするとその分のheightが失われるので、$headerAfterにheaderY分のmarginを設定します。
function _fixed(){
$header.css({
'position': 'fixed',
'top': 0,
'left': 0
});
$headerAfter.css('marginTop', headerY);
};
// $headerにstaticを設定し、デフォルトの挙動に戻します。
// $headerをstaticにするとheightが戻るので、$headerAfterのmarginをリセットします。
function _static(){
$header.css({
'position': 'static',
'top': '',
'left': ''
});
$headerAfter.css('marginTop', '');
};
};
/*
* ! 関数loadを作成
* 非表示にしていたDOMを表示させる関数
*/
function load(){
// 非表示にしているDOMを配列に入れます。
var array = [$element, $next, $prev];
// 配列に入っているDOMを全て表示します。
for(var i = 0; i < array.length; i++) array[i].css('visibility', 'visible');
// CSSで$containerの背景画像に設定していたloading.gifをリセットします。
$container.css('background', 'none');
};
// windowのloadイベントを登録します。
// ロードが完了したら関数initializeを実行します。
$window.on('load', initialize);
}());
[/javascript]
今回のサンプルデータはWebDesigningのサイトにございます。
http://book.mycom.co.jp/wd/2012/12.html
第1回目のjQuery Labはいかがでしたでしょうか?
これからもいろいろ勉強して、すぐに役立つサンプルを取り上げていきたいと思いますのでよろしくお願いいたします。
この記事を書いた人
著者 : ハヤシユタカ
2001年、有限会社ムーニーワークスを設立。WEB制作の他、書籍執筆、セミナー講演、企業研修などを行う。また、クリエイター育成機関デジタルハリウッドでは1999年より講師として本科WEBデザイナーコースやデジタルデザインコースを担当。 詳しいプロフィールはこちら