少し前に「jQueryでレスポンシブメニューをアコーディオンタイプでシンプルに実装する方法」と題して、スマートフォン向けレイアウト時ではメニューをアコーディオン動作で展開するレスポンシブナビゲーションUIを紹介しました。

レスポンシブナビゲーションUIのパターンとしてはアコーディオン動作ではなく
ハンバーガーメニューボタンを使って、画面のサイドからメニューボタンを
スライドさせて表示させるタイプもあります。

今回はその画面横からスライドさせて
メニューボタンを展開するタイプのレスポンシブメニューUIを
jQueryを使ってできるだけシンプルな構成で作ってみたのでご紹介してみます。

jQueryでレスポンシブメニューを横スライドタイプでシンプルに実装する方法

「jQueryでレスポンシブメニューを横スライドタイプでシンプルに実装する方法」サンプルを別枠で表示

サンプルでは前回同様に
ウィンドウサイズが768px以上ならばPC向けナビゲーション、
768px以下だったらスマートフォン向けのナビゲーションに切り替わります。

PC向けナビゲーションではボタン類は画面内に横並びですべて表示されます。
スマートフォン向けナビゲーションではページ上部に
ハンバーガーメニューボタンを配置しクリックすることで
画面横からスライド動作によってボタン類が出現します。

全体構成についてまずはHTMLから。

◆HTML
<nav id="menuList">
<ul>
<li><a href="#">[1] MENU</a></li>
<li><a href="#">[2] MENU</a></li>
<li><a href="#">[3] MENU</a></li>
<li><a href="#">[4] MENU</a></li>
<li><a href="#">[5] MENU</a></li>
</ul>
</nav><!-- /#menuList -->

HTMLではナビゲーションで使用するリンクボタンをリストで構成し、
リスト全体を任意のIDもしくはクラスで囲います。

PC向けレイアウトでもスマートフォン向けでも
この一つのHTMLソースを使用します。

この要素に対してCSSは以下のように指定します。

◆CSS
/* ------------------------------
   #menuList
------------------------------ */
#menuList {
	width: 100%;
	height: 45px;
	border-top: #aaa 1px solid;
	border-bottom: #aaa 1px solid;
	position: relative;
	z-index: 10;
	background: #ebebeb;
}

#menuList ul {
	margin: 0 auto;
	width: 800px;
	height: 45px;
	text-align: left;
}

#menuList ul li {
	width: 160px;
	height: 45px;
	float: left;
	border-left: #aaa 1px solid;
	box-sizing: border-box;
}

#menuList ul li:last-child {
	border-right: #aaa 1px solid;
}

#menuList ul li a {
	height: 45px;
	font-weight: bold;
	line-height: 45px;
	display: block;
	text-align: center;
	transition: all 0.2s linear;
}

#menuList ul li:hover > a {
	background: #fff;
}

#contents {
	margin: 0 auto;
	padding: 40px 0;
	width: 800px;
	text-align: left;
}

#contents p {
	padding-bottom: 2em;
	font-size: 1em;
	line-height: 2em;
}

/* ------------------------------
   MEDIAQUERIES LAYOUT
------------------------------ */
@media only screen and (max-width: 800px) {
	#menuList ul {
		width: 100%;
	}

	#menuList ul li {
		width: 20%;
	}
}

/* ------------------------------
   MEDIAQUERIES[SP]LAYOUT
------------------------------ */
@media only screen and (max-width: 768px) {
	#menuList {
		display: none;
	}

	#menuOverlay {
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
		background-color: rgba(0,0,0,0.6);
		display: none;
		position: fixed;
		z-index: 9997;
	}

	#switchBtnArea {
		width: 100%;
		height: 60px;
		background: #3c3c3c;
		border-bottom: #aaa 1px solid;
		position: relative;
	}

	#switchBtnArea #switchBtn {
		top: 10px;
		left: 10px;
		width: 40px;
		height: 40px;
		display: block;
		background: #a7a7a7;
		position: absolute;
		border-radius: 5px;
		z-index: 9998;
	}

	#switchBtnArea #switchBtn span {
		left: 20%;
		width: 60%;
		height: 4px;
		display: block;
		position: absolute;
		background-color: #fff;
		border-radius: 5px;
		transition: all 0.2s linear;
	}
	#switchBtnArea #switchBtn span:nth-of-type(1) {
		top: 10px;
		-webkit-transform: rotate(0);
		transform: rotate(0);
	}
	#switchBtnArea #switchBtn span:nth-of-type(2) {
		top: 18px;
		-webkit-transform: scale(1);
		transform: scale(1);
	}
	#switchBtnArea #switchBtn span:nth-of-type(3) {
		bottom: 10px;
		-webkit-transform: rotate(0);
		transform: rotate(0);
	}

	#switchBtnArea #switchBtn.btnClose {
		background: transparent;
	}
	#switchBtnArea #switchBtn.btnClose span:nth-of-type(1) {
		top: 18px;
		-webkit-transform: rotate(-45deg);
		transform: rotate(-45deg);
	}
	#switchBtnArea #switchBtn.btnClose span:nth-of-type(2) {
		-webkit-transform: scale(0);
		transform: scale(0);
	}
	#switchBtnArea #switchBtn.btnClose span:nth-of-type(3) {
		bottom: 18px;
		-webkit-transform: rotate(45deg);
		transform: rotate(45deg);
	}

	#rwdMenuWrap {
		top: 0;
		left: -200px;
		width: 200px;
		height: 100%;
		background: #3c3c3c;
		overflow: auto;
		position: fixed;
		z-index: 9999;
	}

	#rwdMenuWrap ul {
		width: 100%;
	}

	#rwdMenuWrap ul li {
		width: 100%;
		border-bottom: #aaa 1px solid;
	}

	#rwdMenuWrap ul li a {
		padding: 15px 20px;
		text-align: left;
		display: block;
		background: #ebebeb;
		position: relative;
	}

	#rwdMenuWrap ul li a:after {
		content: '';
		margin-top: -4px;
		top: 50%;
		right: 15px;
		width: 8px;
		height: 8px;
		color: #888;
		font-size: 1em;
		font-weight: bold;
		line-height: 1.2em;
		display: block;
		position: absolute;
		border-top: 2px solid #b0b0b0;
		border-right: 2px solid #b0b0b0;
		-webkit-transform: rotate(45deg);
		transform: rotate(45deg);
	}

	#contents {
		width: 100%;
	}

	#contents p {
		padding: 0 20px 2em 20px;
	}
}

/* ------------------------------
   CLEARFIX ELEMENTS
------------------------------ */
#menuList > ul:before,
#menuList > ul:after {
	content: " ";
	display: table;
}
#menuList > ul:after {clear: both;}
#menuList > ul {*zoom: 1;}

768px以上のPC向けレイアウトでは
ボタンを横並びにするプロパティを指定します。

768px以下のスマートフォン向けレイアウトでは
PC向けレイアウト時に使用している要素は「display:none;」で非表示にします。

スクリプト側でメニューボタンのソースを
「#switchBtnArea」にコピーして制御します。

リスト要素を囲う「#rwdMenuWrap」を「posiiotn:fixed」にして位置固定し
「left」の値を要素幅と同じ値分「-(マイナス)」で指定し
画面の外へ隠しておきます。

ハンバーガーメニューボタンの装飾・アニメーションと
コンテンツエリアとナビゲーションメニューエリアの間に挟まることになる
オーバーレイ要素「#menuOverlay」に対しても背景色等を指定します。

そして実際の切り替えスクリプトは以下の様になります。

◆SCRIPT
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>
$(function(){
	var rwdMenu = $('#menuList'),
	switchPoint = 768,
	slideSpeed = 300,
	fadeSpeed = 500;

	var menuSouce = rwdMenu.html();

	$(window).load(function(){

		function menuSet(){
			if(window.innerWidth <= switchPoint){
				if(!($('#rwdMenuWrap').length)){
					$('body').prepend('<div id="menuOverlay"></div><div id="switchBtnArea"><a href="javascript:void(0);" id="switchBtn"><span></span><span></span><span></span></a></div><div id="rwdMenuWrap"></div>');
					$('#rwdMenuWrap').append(menuSouce);

					var menuOverlay = $('#menuOverlay'),
					switchBtn = $('#switchBtn'),
					btnLeft = parseInt(switchBtn.css('left')),
					menuWrap = $('#rwdMenuWrap'),
					menuWidth = menuWrap.outerWidth();

					switchBtn.on('click', function(){
						if($(this).hasClass('btnClose')){
							$(this).removeClass('btnClose').removeAttr('style');
							menuOverlay.stop().animate({opacity:'0'},fadeSpeed,function(){
								menuOverlay.removeAttr('style');
							});
							menuWrap.stop().animate({left:'-' + menuWidth + 'px'},slideSpeed);
							$('body').removeAttr('style');
						} else {
							$(this).addClass('btnClose').css({position:'fixed'}).stop().animate({left:menuWidth + btnLeft},slideSpeed);
							menuOverlay.css({display:'block',opacity:'0'}).stop().animate({opacity:'1'},fadeSpeed);
							menuWrap.stop().animate({left:'0'},slideSpeed);
							$('body').css({position:'fixed'});
						}
					});
				}
			} else {
				$('#menuOverlay,#switchBtnArea,#rwdMenuWrap').remove();
				$('body').removeAttr('style');
			}
		}

		$(window).on('resize', function(){
			menuSet();
		});

		menuSet();
	});
});
</script>

スクリプト開始部分にある設定値の内容は以下の様になっています。

rwdMenu = $(‘#menuList’) 切り替えUI全体を囲う要素(CSSクラスでも可)
switchPoint = 768 PC向けとスマートフォン向けで切り替えるサイズ
slideSpeed = 300 メニュー開閉時のスライドアニメーション時間
fadeSpeed = 500 オーバーレイ要素が出現する際のフェードアニメーション時間

これらの設定値を変更することで微調整が可能になっています。
「switchPoint」で設定する値は、CSSで設定したメディアクエリと同じ値にします。

ページロード時およびウィンドウリサイズ時に
ウィンドウサイズを取得します。

「switchPoint」で設定された値(サンプルでは768px)よりも大きい
PC向けレイアウトの場合はスクリプト側では特になにもしません。

「switchPoint」で設定された値よりも小さければ
スマートフォン向けメニューとしてのソースをオーバーレイ要素と合わせて生成し
ハンバーガーメニューのボタンクリック時の開閉動作を指定します。

スマートフォン向けメニューソースは
「switchPoint」で設定された値よりも大きい場合は
要素自体を削除します。(生成させません)

以上がスライドタイプのレスポンシブ対応メニューUIを
jQueryでシンプルに実装する紹介でした。

レスポンシブWebサイトでナビゲーションメニューを
コンパクトに扱う場合になどに活用できるUIかと思っています。

PC向けとスマートフォン向けでナビゲーションメニューUIを
スライドタイプで切り替える際にぜひ。。。

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

SHARE

Comments (10)

  • tone | 2016.07.29 10:33

    こんにちは。

    少し前に、

    jQueryでレスポンシブメニューをアコーディオンタイプでシンプルに実装する方法
    https://black-flag.net/jquery/20160119-5897.html

    にコメントさせていただきました者ですが、

    こちらの仕様でも、メニューを上部に固定する方法を教えていただければ幸いです。

    お手数ですが、よろしくお願い致します!

  • BlackFlag | 2016.07.31 1:20

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

    もう一つの方で返答させていただいた内容とほぼ同じになりますが
    メニューの上部固定はスクリプトから指定するのではなく
    CSSのみで対応させることが可能かと思いますので
    メニューボタン要素となる「#switchBtnArea」に対して
    「position:fixed」と「z-index」のプロパティを追加するなどして
    調整いただければと思います

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

  • milly | 2016.08.14 1:23

    初めまして!

    こちらのハンバーガーメニュー(switchBtnArea)についてですが、

    ”menuList”とは別の内容(他のコンテンツリンクへ飛ばしたい)を入れたいのですが、

    どのようにすればよろしいでしょうか?

    お手数ですが宜しくお願い致します。

  • BlackFlag | 2016.08.14 13:30

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

    当記事のスクリプトはPC用とスマホ用で
    同じメニューソースの形状を変える、という構成になっておりますので、
    ご質問いただきましたような、PC用とスマホ用でそれぞれ違う構成のメニュー切り替えを考えると
    当記事のスクリプトを使用せずに、
    HTMLにPC用とスマホ用のメニューソースをそれぞれ記載して
    CSSメディアクエリーで表示/非表示を切り替える方が
    適切なのではないかと思っております。

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

  • 浅井 | 2017.06.19 21:12

    はじめまして

    こちらのスクリプトは階層形式のメニューには対応されていますか?
    もしされていないのであれば対応方法を教えていただけると助かります。

    よろしくお願いします。

  • BlackFlag | 2017.06.25 9:51

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

    当記事のスクリプト構成では、
    階層形式のメニューでの実装は想定しておりません。

    ですが、このスクリプトを応用して
    そのようなレスポンシブメニューを作成することは可能だと思いますので
    またサンプル等を用意することができましたら
    ここで紹介させていただきたいと思います。

    よろしくお願いします。

  • 佐々木歩美 | 2017.10.03 12:40

    はじめまして!
    WEBデザイナーをしております。

    こちら実装させていただきました。
    ありがとうございます。

    1つおうかがいしたいのですが、
    メニューの数が多くなった場合、
    スマホですと下の方が見えなくなってしまうのですが、
    メニュー部分をスクロールさせる方法はあるでしょうか?

  • BlackFlag | 2017.10.07 11:18

    >佐々木歩美さん
    コメントありがとうございます。
    当記事のメニュースクリプトをご活用いただいているようで
    うれしく思っております。

    メニュー数が多くなった場合でも
    スクロールして下が見える構成になっていると思いますが
    お使いのデバイスでそのような動作にならない場合は
    一度ご確認いただいているデバイスの情報(OS+端末名)を
    お知らせいただければと思います。

    iPhoneではスクロールバーは表示されませんが
    メニュー部分をスワイプすることで下の方が表示されるかと思います。

    ご確認ください。
    よろしくお願いします。

  • | 2017.12.12 17:21

    初めまして。色々と探しまくってここにたどり着きました。

    とてもすばらしいものだと思いました。

    そこで、私もこのソースを組み込んで確認してた所、いくつか問題点が出てきたのでご質問します。

    1.<li>の1番目をタイトルとして指定したい。(「>」も消したい)
    2.メニュー幅を大きくすると「✕」が隠れてしまう。
    3.<li>に<li:nth-child>で画像をつけると(これは何番目には**の画像をなど複数個あり)、メニューが左右にスライドして固定されない。(スマホで)

    我が儘な質問かもしれませんが、是非、ご教授願います。

    当方、スクリプトの知識が無いので困っております。
    宜しくお願いします。

  • BlackFlag | 2017.12.23 9:39

    >渚さん
    コメントありがとうございます。
    当記事のメニュースクリプトをご活用いただいているようで
    うれしく思っております。

    ご質問いただきました件についてですが、
    実際に実装されようとしているものを見てみないと状況も判断しにくいのですが
    PC時の表示構成とは別のものをスマホの際に表示するということでしょうか。

    2、3についてはCSSの指定方法の問題かと思われますが
    実際に組まれているものを拝見させていただければ
    問題点も見出せるかと思います。

    よろしくお願いします。







コメント内容

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

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