iPhoneやiPad、Androidといったスマートフォンやタブレット端末では
フリック/スワイプと呼ばれる指でスライドさせるUIが付き物になっています。
jQueryでもこのフリック/スワイプ動作を実装できるプラグインはたくさんありますが
いざ自分で作ろうとすると意外と大変な動作だったりします。

この動作についていろいろ調べていたところ
Sleipnirのフェンリルさんのデベロッパーズブログにて、

iPhone/Android/PC 対応。jQuery で書くタッチイベント (フェンリル | デベロッパーズブログ)

と題した、jQueryでiPhoneやAndroid、PCでタッチイベントを取得する方法がとても参考になったので
この記事を参考にしてフリック/スワイプで操作するシンプルな画像ギャラリーを作ってみました。

jQueryでフリック/スワイプ動作の画像スライドギャラリーを作成する実験

まずは動作サンプルから。
下記の画像をフリック/スワイプしてみてください。
※PCのマウス操作でも動作します。

別枠で表示する場合はこちらから

拡大画像部分を左右にフリック/スワイプすることで
画像が一枚一枚スライドします。

この動作の全体構成について、
HTMLから。

◆HTML
<div id="flickscroll">
<ul>
<li><img src="img/photo01.jpg" width="400" height="400" alt="" /></li>
<li><img src="img/photo02.jpg" width="400" height="400" alt="" /></li>
<li><img src="img/photo03.jpg" width="400" height="400" alt="" /></li>
<li><img src="img/photo04.jpg" width="400" height="400" alt="" /></li>
</ul>
</div><!--/#flickscroll-->

<div id="flickthumb">
<ul>
<li><img src="img/photo01.jpg" width="100" height="100" alt="" /></li>
<li><img src="img/photo02.jpg" width="100" height="100" alt="" /></li>
<li><img src="img/photo03.jpg" width="100" height="100" alt="" /></li>
<li><img src="img/photo04.jpg" width="100" height="100" alt="" /></li>
</ul>
</div><!--/#flickthumb-->

上部の<div id=”flickscroll”>がメイン部分にあたるソースになり、
下部の<div id=”flickthumb”>がサムネイル部分になります。
2つの<div>の中にはそれぞれにリストを入れ込みます。(ID名は変更可能)

HTMLはメイン用とサムネイル用の<div>と<ul>リストを用意するのみです。
リストの数はいくつでも増減可能です。

そしてこのHTMLソースに対してのCSSは以下の様に。

◆CSS
/* #flickscroll
--------------------------- */
#flickscroll {
	margin: 0 auto;
	width: 400px;
	height: 400px;
	text-align: left;
	position: relative;
	overflow: hidden;
	cursor: pointer;
}
#flickscroll ul {
	top: 0;
	left: 0;
	height: 400px;
	position: absolute;
	overflow: hidden;
}
#flickscroll ul li {
	width: 400px;
	height: 400px;
	float: left;
	display: inline;
	overflow: hidden;
}

/* #flickthumb
--------------------------- */
#flickthumb {
	margin: 10px auto;
	width: 400px;
	height: 100px;
	text-align: center;
}
#flickthumb ul {
	width: 400px;
	height: 100px;
}
#flickthumb ul li {
	width: 100px;
	height: 100px;
	float: left;
	cursor: pointer;
	display: inline;
}
#flickthumb ul li.active {
	filter:alpha(opacity=100)!important;
	-moz-opacity: 1!important;
	opacity: 1!important;
}


/* =======================================
	ClearFixElements
======================================= */
#flickscroll ul:after,
#flickthumb ul:after {
	content: ".";
	height: 0;
	clear: both;
	display: block;
	visibility: hidden;
}

#flickscroll ul,
#flickthumb ul {
	display: inline-block;
	overflow: hidden;
}

実際のフリック/スワイプ動作させる箇所「#flickscroll」で
全体の幅と高さの表示サイズを指定しています。

全体を囲うID「#flickscroll」の中に入る
リスト<ul>は「position:absolute」で絶対位置にして、
幅widthは<li>の数によってスクリプト側で計算して入れるので
ここでは指定しないようにしています。

サムネイル箇所「#flickthumb」については
とくにスクリプト動作には影響しないレイアウト調整のみになっています。

そして実際に動作を実行させるスクリプトは以下の様になります。

◆SCRIPT
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	var $setMainId = $('#flickscroll');
	var $setThumbId  = $('#flickthumb');
	var scrollSpeed  = 300;

	var $setMainUl = $setMainId.children('ul'),
	$setThumbUl = $setThumbId.children('ul'),
	$setThumbLi = $setThumbUl.children('li'),
	$setThumbLiFirst = $setThumbUl.children('li:first'),
	listWidth = parseInt($setMainUl.children('li').css('width')),
	listCount = $setMainUl.children('li').length,
	leftMax = -((listWidth)*((listCount)-1));

	$setMainUl.each(function(){
		$(this).css({width:(listWidth)*(listCount)});
	});

	var isTouch = ('ontouchstart' in window);
	$setMainUl.bind(
		{'touchstart mousedown': function(e){
			var $setMainUlNot = $setMainId.children('ul:not(:animated)');
			$setMainUlNot.each(function(){
				e.preventDefault();
				this.pageX = (isTouch ? event.changedTouches[0].pageX : e.pageX);
				this.leftBegin = parseInt($(this).css('left'));
				this.left = parseInt($(this).css('left'));
				this.touched = true;
			});
		},'touchmove mousemove': function(e){
			if(!this.touched){
				return;
			}
			e.preventDefault();
			this.left = this.left - (this.pageX - (isTouch ? event.changedTouches[0].pageX : e.pageX) );
			this.pageX = (isTouch ? event.changedTouches[0].pageX : e.pageX);

			if(this.left < 0 && this.left > leftMax){
				$(this).css({left:this.left});
			} else if(this.left >= 0) {
				$(this).css({left:'0'});
			} else if(this.left <= leftMax) {
				$(this).css({left:(leftMax)});
			}
		},'touchend mouseup mouseout': function(e){
			if (!this.touched) {
				return;
			}
			this.touched = false;

			var $setThumbLiActive = $setThumbUl.children('li.active');

			if(this.leftBegin > this.left && (!((this.leftBegin) === (leftMax)))){
				$(this).stop().animate({left:((this.leftBegin)-(listWidth))},scrollSpeed);
				$setThumbLiActive.each(function(){
					$(this).removeClass('active');
					$(this).next().addClass('active');
				});
			} else if(this.leftBegin < this.left && (!((this.leftBegin) === 0))) {
				$(this).stop().animate({left:((this.leftBegin)+(listWidth))},scrollSpeed);
				$setThumbLiActive.each(function(){
					$(this).removeClass('active');
					$(this).prev().addClass('active');
				});
			} else if(this.leftBegin === 0) {
				$(this).css({left:'0'});
			} else if(this.leftBegin <= leftMax) {
				$(this).css({left:(leftMax)});
			}
		}
	});

	$setThumbLi.click(function(){
		var connectCont = $setThumbLi.index(this);
		$setMainUl.stop().animate({left:(-(listWidth)*(connectCont))},scrollSpeed);
		$setThumbLi.removeClass('active');
		$(this).addClass('active');
	});

	$setThumbLiFirst.addClass('active');
	$setThumbLi.css({opacity:'0.5'});

	var agent = navigator.userAgent;
	if(!(agent.search(/iPhone/) != -1 || agent.search(/iPad/) != -1 || agent.search(/iPod/) != -1 || agent.search(/Android/) != -1)){
		$setThumbLi.hover(function(){
			$(this).stop().animate({opacity:'1'},300);
		},function(){
			$(this).stop().animate({opacity:'0.5'},300);
		});
	}
});
</script>

メイン部分の<div>要素の幅と高さの値を元に
フリック/スワイプ動作でスライドさせる<ul>の幅やスライドさせる距離など計算しています。

スクリプト開始部分にある
————————————————
var $setMainId = $(‘#flickscroll’);
var $setThumbId = $(‘#flickthumb’);
var scrollSpeed = 300;
————————————————
は上から
————————————————
・該当するメインエリアのID名
・該当するサムネイルエリアのID名
・フリック/スワイプ動作でスライドさせた時のスライドスピード
————————————————
となっているので、
値を変更することでカスタマイズが可能です。

メインエリア(画像)部分のアクションで
————————————————
・タッチした時
・タッチしたまま移動している時
・タッチが離れた時
————————————————
の3点でのそれぞれの値を見て
処理を加えてあります。

この3点での値を取得する方法が分かれば
画像ギャラリーのみでなく、いろいろなフリック/スワイプ操作での
UIが実装できるように感じています。

サンプルの動作環境は
・Windows
 IE6,7,8
 Forefox
 Google Chrome
 Safari

・Mac
 Firefox
 Safari

・iPhone
・iPad/iPad2
・Android
以上の動作で確認済みです。

jQueryでフリック/スワイプ動作のスライドギャラリーを作成する際に是非。。

サンプルファイルをダウンロードしたい方はこちらから

SHARE

Comments (18)

  • jQueryでフリック/スワイプ動作の画像スライドギャラリーを作成する実験 | BlackFlag | WordBuff.in | 2012.03.07 10:17

    […] jQueryでフリック/スワイプ動作の画像スライドギャラリーを作成する実験 | BlackFlag: jQueryでフリック/スワイプ動作の画像スライドギャラリーを作成する実験 | BlackFlag […]

  • jQueryでフリック/スワイプ付きの自動再生スライドショーを作成する実験 | BlackFlag | 2012.03.14 10:45

    […] 前回の記事で、iPhoneやiPad、Androidなどに加えてPCでも動作する フリック/スワイプ動作UIをjQueryで実装する方法を紹介しましたが、 前回の単純なフリック/スワイプのUI動作に加えて、 […]

  • gogoisu | 2013.04.03 12:41

    はじめまして。
    見ていると、色々と利用出来そうなことを思いつき、
    非常に参考にさせてもらっています。

    こちらのスクリプトを利用しようと検証しておりますが・・・
    リンクを設置するとPCではうまくいきますが、タブレット端末だリンクが反応しません。
    しかたがないのでしょうか。

    ご教示いただけると幸いです。
    よろしくお願いします。

  • BlackFlag | 2013.04.06 23:21

    >gogoisuさん
    コメントありがとうございます。

    ご質問いただきました内容についてですが
    このスクリプトではフリック箇所に関しての
    リンク要素についての対処はしていないので
    画像にリンクを張っても正常に動作しません・・・

    タッチイベントとクリックイベントの対処にも対応したパターンも出来次第、
    ここで紹介させていただきたいと思っておりますが
    現状まだ用意できておりません。。

    申し訳ないのですが
    何卒よろしくお願いします。。

  • gogoisu | 2013.07.02 10:07

    返信が遅くなってしまって申し訳ありません。

    ご回答いただきどうもありがとうございます。

    「BlackFlag 」さんのサイトはみていて、非常に勉強になります。
    よさそうなサンプルがあったら、また参考にさせてください。

  • Yuzy | 2013.10.03 20:32

    初めてコメントさせて頂きます。
    Yuzyと申します。

    いつも参考にさせて頂いております。ありがとうございます。

    早速ではございますが本ソースコード上では
    最初の画像を何番目の画像にする、といった設定は可能でしょうか?

  • BlackFlag | 2013.10.06 23:59

    >Yuzyさん
    コメントありがとうございます。

    ご質問いただいた件についてですが
    ご希望されている設定構成を把握しきれておりませんが
    当記事で紹介しているスクリプトでは
    表示する画像の順番はHTML側で記述する構成になっておりますので
    そちらで並び順を調整していただく形になります。

    よろしくお願いします。

  • shio | 2014.01.24 19:07

    分かりやすく参考にさせて頂いています。
    初心者なので、分からないことだらけでとても助かっています。

    写真が多くなった時、(10枚など)サムネイル部分の画像が最初の4枚しか表示されません。
    全て表示したい、もしくは画像ではなくドット?で対応したい時はどうようにすればよろしいでしょうか?
    他のページにもし説明がありましたら重複で申し訳ありません。

  • BlackFlag | 2014.01.26 11:30

    >shioさん
    コメントありがとうございます。
    このフリックスライドショーをご活用いただいている様で
    嬉しく思っております。

    ご質問いただいた件についてですが
    サムネイル部分の見た目(レイアウト)に関しては
    スクリプト側での制御ではなくCSSで調整する形になります。

    CSSの「#flickthumb」部分のサイズ等を調整することで
    サムネイルを全て表示することが可能ですので
    実装しようとしているされているレイアウトに合わせて
    調整してみてください。

    サムネイルをドットにする際も
    当記事のスクリプト構成の場合は
    サムネイル部分の画像をドット画像にして
    CSSでサイズ等を調整する形になっております。
    (自動ページネーション付与機能は付いておりません・・・)

    よろしくお願いします。

  • egao | 2014.01.28 23:29

    はじめまして、にゃん大好きなegaoです=^.^=

    とてもシンプルなスライダーですね。
    今まで、jquery.touchslider.jsというプラグインを検討していましたが、
    早速、乗り換えることにしました。

    javascript側のグローバル変数に対して
    現在表示している画像番号をjQuery側から出力する方法と
    表示したい画像番号を
    javascript側からjQuery側へ指定する方法について
    教えてください。

    よろしくお願いします。

  • egao | 2014.02.01 0:17

    egaoです。
    先日の問い合わせの件は、自己解決しました。
    スクリプトを眺めていたら、変数の意味が分かってまいりました。

    画像番号を出力する方法は、
    this.leftBeginをlistWidthで除算すれば得られました。
    画像番号を指定する方法は、
    $(this).css(‘left’)を最初に画像番号*画像幅分だけ
    ずらすことにしました。

    お騒がせしました。
    いいscriptを公開して頂きありがとうございます。

  • otzi | 2014.07.31 12:46

    こんにちは。
    個人・商用問わず使用可とのことですが、運営する商用サイトに併設の個人ブログで使わせていただきました。
    ウチのサイトに組み込んでいるjqueryのバージョンは少し古いのですが、それでも問題なく動作します。
    PCのマウス操作でも動作するし、カスタマイズも容易で用途はとても広いのではないかと思います。
    今後はサイト本体での利用も検討してみたいと思います。
    以上、はなはだ簡単ですがお礼並びに御報告と致します。

  • BlackFlag | 2014.08.01 1:59

    >otziさん
    コメントありがとうございます。
    当記事のフリックスライドショーをご活用いただいている様で
    嬉しく思っております。

    そのようなお言葉をいただけると
    とても嬉しく励みになります。

    ほかにもいろいろと紹介させていただいておりますので
    Webサイト制作の際にあれこれお試しいただけると幸いです。

    よろしくお願いします。

  • スマホサイト作成時に役立つプラグイン集 | モノづくりブログ - 株式会社8bit | 2015.07.08 13:20

    […] サイトへ タップやスワイプに対応しているスライドショーです。 […]

  • FUKU | 2015.11.01 0:06

    こちらのサイトは、シンプルで使いやすそうなものばかりなので、
    初心者なのに、ついつい色々試してみたくなります。

    このスライドショーを是非使わせていただこうと設置してみたら、
    簡単に動作確認までできました!本当に丁寧でわかりやすいです。

    ただ、私の問題なのですが、写真の数がとても多く、
    サムネイルを小さくしても入りきれず2段になってしまいました。
    そこでサムネイル部分をスクロールすることは可能でしょうか?
    実際には、インラインフレームでこのスライドショーを表示しようと考えていますので
    今後もっと写真が増えたとしても、スクロールすれば問題ないかな?と思ったのですが
    そんなことは可能でしょうか?また写真が多いと何か問題がありますでしょうか?
    お時間のあるときによろしくおねがいします。

  • BlackFlag | 2015.11.01 12:36

    >FUKUさん
    コメントありがとうございます。
    そのようなお言葉をいただけると
    とても嬉しく励みになります。

    当記事のスライドショーのサムネイル部分は
    特にその様な仕様にはしておりませんが
    別途サムネイル部分にカルーセルなどのスクリプトを
    組み合わせて実装することで可能になるかと思います。

    写真の数に関しては
    多くなればその分ページの負荷にもなるので
    ある程度の数に絞った方がいいですが
    スクリプト動作自体には影響は無いかと思います。

    お試しください。
    よろしくお願いします。

  • miki | 2015.12.18 13:05

    初めてコメントさせて頂きます。
    mikiと申します。
    初心者の私でも理解できるので、いつも参考にさせていただいております!
    ありがとうございます!

    こちらのスライドショーですが、
    左から右へスワイプしていくようになっていますが、
    右からスワイプしていくようにすることは可能でしょうか?

    よろしくお願いします。

  • BlackFlag | 2015.12.21 2:11

    >mikiさん
    コメントありがとうございます。
    当記事のフリックスライドショーをご活用いただいている様で
    うれしく思っております。

    「右からスワイプしていくようにする」というのが
    どのような動作のことを想定しているのか少々不明なのですが
    スクリプトの最後に
    ————————-
    $setThumbUl.children(’li:last’).click();
    ————————-
    のような記述を入れておけば、
    スライドするアニメーションは見えてしまいますが、
    ページロード時には、末端のリストが表示され
    右からスワイプする形になります。

    お試しください。
    よろしくお願いします。







コメント内容

※コメントにHTMLタグを直接入力しないでください。
※HTMLタグを入力する際はタグ一つ一つの括弧「<」「>」を全角に変換して入力してください。

コメントは承認制になっているのですぐには反映されません。コメント頂いた内容については出来る限り早めの対応を心掛けていますが、時期によって返答が遅くなってしまうことがありますので、何卒ご了承ください。
» コメントについてのご注意  |  » ライセンスに関して