読者です 読者をやめる 読者になる 読者になる

Develop and Design Note

フロントエンドなデザイナーの覚書

レスポンシブWebデザインでカルーセルを実装してみた

フォトギャラリーなどでよく使われるカルーセルをレスポンシブWebデザインで試しみました。

レスポンシブ&モーダル&カルーセル

完成品はこちら
写真をクリックすると、モーダルウィンドウが開き、その中でカルーセルが動きます。これがレスポンシブであるが故に苦労し、実装に3日くらいかかりました。

こちらJavaScriptのソースなのですが、以下の順で大きな5つの処理が走ります。

  1. img要素の情報を取得してfigure要素として出力
  2. インジケーターの数字出力
  3. モーダルウィンドウを開く
  4. モーダルウィンドウを閉じる
  5. 左右ボタンでスライド

これら5つの処理の順番が違ったり、5の処理の中に3・4を書いてしまったりすると上手く機能せず、苦労したわけです。

1)img要素の情報を取得してfigure要素として出力

// 1)img要素の情報を取得してfigure要素として出力
$(thumbImg).each(function(i) {
	var photo = $(this).attr('src'),
		text = $(this).attr('alt'),
		i = i+1,
		figureElm = '<figure class="no'+i+'"><img src="'+photo+'" width="100%"><figcaption>'+text+'</figcaption></figure>';
	$(modalFigureWr).append(figureElm);
});
var modalFigure = '#vol .modalWrWr figure';
$(modalFigure).last().prependTo(modalFigureWr);// 最後のfigure要素を先頭に移動

「$(thumbImg)」には、写真のサムネイルにあたるimg要素が入ります。そのimg要素の属性情報を取得して、「figureElm=”」内に書いたhtmlとして出力します。

このhtmlがモーダルウィンドウ内に表示されるのですが、img要素は全部で21個あるので、each関数を使って全てのimg要素に対し、同様の処理を走らせます。こうすることで、カルーセルさせるfigure要素の繰り返し構造ができあがります。

そして、繰り返しされている最後のfigure要素を「prependTo」を使って、先頭に移動させることで、カルーセルの左右スライドに備えます。

2)インジケーターの数字出力

// 2)インジケーターの数字出力
function photoNum() {
	var figureClassName = $(modalFigure).first().next().attr('class'),
		figureNum = figureClassName.slice(2);
		$(modalPhotoNum).text(figureNum);
};
photoNum();

サムネイルをクリックすると開くモーダルウィンドウ内に、「3/21」など、全ての写真のうちの何枚目かを示す処理です(インジケーターとは意味が違うかも)。

これは、「先ほど出力処理をしたfigure要素に含まれるclass名から数字のみを抜き出す」という関数です。なので、さきほどのeach関数には引数「i」を設定し、class名に出力する記述「

」を書いています。

3)モーダルウィンドウを開く

// 3)モーダルウィンドウを開く
$(thumb).click(function(e) {
	$(modalWindow).css('display','block');
	var clickThumb = $(thumb).index(this);// クリックした要素のindex(先頭から何番目か)を取得
	if (clickThumb === 0) {
		var clickThumb = 21;
	}else if(clickThumb === 1){
		var clickThumb = 22;
	};
	var clickThumb = clickThumb-1,// 取得したindex番号を−1ずらす
		prevFigure = $(modalFigureWr).find('.no'+clickThumb),// クリックした要素の1つ手前に該当するfigure要素を取得 
		movingFigures = $(prevFigure).nextAll();// そのfigure要素を含む以降のfigure要素を全てを取得
	$(movingFigures).prependTo(modalFigureWr);// 先頭に移動させる(2番目の要素がカルーセル内に見える)
	function modalWindowFigure(){// モーダルウィンドウ画像幅の取得と出力
		modalFigureWidth = $(modalFigureWrWr).width();// グローバル変数
		$(modalFigureWr).css('margin-left',-+modalFigureWidth+'px');//ネガティブマージンで写真1つ分左にずらす
		$(modalFigureWrWr).css('width',modalFigureWidth);// 数pxのズレを防ぐためwidth値を%からpxに変換する
		$(modalFigure).css('width',modalFigureWidth);
	};
	modalWindowFigure();
	$(window).resize(function(){
		modalWindowFigure();
	});
	photoNum();// インジケーターの数字出力
	e.preventDefault();
});

サムネイルをクリックした瞬間に走らせる処理ですが、大きく2つあります。「クリックした要素の表示」と「モーダルウィンドウ画像幅の取得と出力」です。「クリックした要素の表示」の処理がないと、どのサムネイルをクリックしても、最初から2番目のfigure要素がモーダル画面に表示されてしまいます。

なので、まず「var clickThumb = $(thumb).index(this)」で、クリックしたサムネイルのインデックスを取得し、「ar prevFigure = $(modalFigureWr).find('.no'+clickThumb)」で、そのインデックスの番号が付与されているfigure要素のclass名を見つけたら、「$(movingFigures).prependTo(modalFigureWr)」で、そのfigure 要素を含む、以降の兄弟要素全てを、順序を保ったまま先頭に移動させます。

こうすることで、クリックしたサムネイルの写真が、モーダルの2番目のfigure要素になります。

次に、「モーダルウィンドウ画像幅の取得と出力」ですが、これが、レスポンシブWebデザインのための処理になります。

モーダルウィンドウの横幅はwidthの値を%指定にしているため、モーダルウィンドウが立ち上がった瞬間に横幅が確定します。なので、横幅の取得はモーダル画面を開いた後に取得する必要があります。その「取得した横幅」の値がそのまま、「モーダル内の画像の横幅」「スライドさせるマージンの横幅」になります。

そして、画面幅を変えてもこれらの処理が有効になるように、resizeイベントも記述します。また、スライドの度にインジケーターの値も変わるので、先ほど作成した関数「modalWindowFigure()」をここでも呼び出します。

4)モーダルウィンドウを閉じる

// 4)モーダルウィンドウを閉じる
$(modalDelete).click(function(e) {
	$(modalWindow).css('display','none');
	e.preventDefault();
});

こちらは特に特筆することはありません。×ボタンを押すことでモーダルウィンドウを閉じます。

ただし、モーダルを閉じた後も、figure要素の順番は維持されたままでリセットされるわけじゃないので、先ほどの「クリックした要素の表示」の処理が必須の実装となります。

5)左右ボタンでスライド

// 5)左右ボタンでスライド
$(modalPrev).bind('click',function(e){//左ボタンで右スライド
	$(modalFigureWr).not(':animated').animate({
		marginLeft:0+'px'
		},200,'linear', 
		function(){
			$(modalFigureWr).css('margin-left',-+modalFigureWidth+'px');
			$(modalFigure).last().prependTo(modalFigureWr);
			photoNum();
		}
	);
	e.preventDefault();
});
$(modalNext).bind('click',function(e){//右ボタンで左スライド
	$(modalFigureWr).not(':animated').animate({
		marginLeft:-+modalFigureWidth*2+'px'
		},200,'linear', 
		function(){
			$(modalFigureWr).css('margin-left',-+modalFigureWidth+'px');
			$(modalFigure).first().appendTo(modalFigureWr);
			photoNum();
		}
	);
	e.preventDefault();
});

最後に、左右ボタンを押したときに、写真をヒュンヒュンとスライド移動させる処理を書きます。

基本的には、「cssのmarginを加算することで横移動させ、その後、figure要素を移動させる」処理を左右ボタンで逆の動きが発生するような記述になります。人によっては、maginでなく、leftやtransformプロパティを使うかもしれません。

そして、レスポンシブの影響を受けるのが、横移動させる「マージンの値」になります。これが先ほどの「モーダルウィンドウ画像幅の取得と出力」で取得した値になるわけです。なので、この1〜5の順序を守らないと、上手く機能しません。


JavaScriptソースは分解して読み解けば、大体のことはわかるかもしれませんが、慣れないうちは、細かい記述を理解するのがなかなか難しいですよね。もう一度同じコード書いてと言われても、スラスラ書ける自信はありません。。修行修行。