レスポンシブサイトでメニュー等のナビゲーションを扱う際、
PC向けレイアウト時にはボタンをページ上に並べ、
スマートフォン向けレイアウト時にはボタン一式を折りたたんで
ハンバーガーボタンでメニューを開閉させる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向けもスマートフォン向けも
この一つのソースを使用します。

この要素に対して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;
	}

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

	#rwdMenuWrap #switchBtnArea {
		width: 100%;
		height: 60px;
		background: #3c3c3c;
		position: relative;
	}

	#rwdMenuWrap #switchBtnArea #switchBtn {
		top: 10px;
		right: 10px;
		width: 40px;
		height: 40px;
		display: block;
		background: #a7a7a7;
		position: absolute;
		border-radius: 5px;
	}

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

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

	#rwdMenuWrap ul {
		width: 100%;
		display: none;
	}

	#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」にコピーして制御するので
CSSではナビゲーションメニュー類を縦に並べて
アコーディオン形式のレイアウトにて指定するのに加えて
ハンバーガーメニューボタンの装飾・アニメーションを指定します。

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

◆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 = 500;

	var menuSouce = rwdMenu.html();

	$(window).load(function(){

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

					var menuList = $('#rwdMenuWrap > ul');

					$('#switchBtn').on('click', function(){
						menuList.slideToggle(slideSpeed);
						$(this).toggleClass('btnClose');
					});
				}
			} else {
				$('#rwdMenuWrap').remove();
			}
		}

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

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

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

rwdMenu = $(‘#menuList’) 切り替えUI全体を囲う要素(CSSクラスでも可)
switchPoint = 768 PC向けとスマートフォン向けで切り替えるサイズ
slideSpeed = 500 メニュー開閉時のアコーディオン動作スライドアニメーション時間

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

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

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

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

HTML上で記載しているメニュー用ソースを
スマートフォン向けに生成されるソースの中にコピーしています。

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

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

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

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

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

SHARE

Comments (18)

  • warashi | 2016.05.02 14:32

    こんにちは。
    いつもありがとうございます。
    スライドショーを使わせていただいております。
    それで、このレスポンシブメニューですが、
    プルダウン時にメニューをクリックしたらプルダウンも同時に閉じるというのは可能でしょうか?
    宜しくお願いいたします。

  • BlackFlag | 2016.05.07 9:52

    >warashiさん
    コメントありがとうございます。
    当記事のレスポンシブメニューをお試しいただいている様で
    嬉しく思っております。

    ご質問いただきました件についてですが
    メニュークリック後は基本的にはページ遷移することになると思われますが
    アンカーリンクの場合などでしょうか…

    メニューをクリックしたらリストが閉じる動作については
    スクリプトの24行目と25行目の間に

    ——————————–
    $(’#rwdMenuWrap ul li a’).on(’click’, function(){
    menuList.slideUp(slideSpeed);
    $(’#switchBtn’).removeClass(’btnClose’);
    });
    ——————————–

    この様な記述を追記すればいけるのではないでしょうか。
    (上記スクリプトは所々全角になっていますがコピペする際にはすべて半角に変換してください)

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

  • wantan | 2016.06.28 16:00

    はじめまして、レスポンシブサイト用にシンプルなメニューを探しておりまして、
    こちらに辿り付きました。
    とてもシンプルかつスムーズな動作でぜひ利用できればと考えているのですが、
    なぜかipadでの表示の際、メニューが全く表示されないという状況に陥っております。
    こちらのサンプルデモでも確認してみましたが、ipadで表示すると
    メニューを表示するハンバーガーマーク自体が表示されていない状況です。
    (PCブラウザの幅を縮小しての確認ですとちゃんと表示されるのですが)
    サイズによる振り分けかと思いますし、css自体も特に原因と思われる怪しい箇所がなく、何故だろう?と疑問に思っております。
    当方htmlとcssくらいしかわからず、jsの記述については検証ができないため、勝手ながらごご報告させていただいた次第です。
    もし何か原因が分かりましたらご助言いただけますと幸いです。

  • BlackFlag | 2016.07.02 11:11

    >wantanさん
    コメントありがとうございます。
    当記事のレスポンシブメニューをお試しいただいている様で
    嬉しく思っております。

    ご指摘いただいた点について
    「switchPoint」で指定したサイズちょうどの地点が
    変換しないポイントとなってしまっておりましたので
    スクリプトを調整させていただきました。

    お手数ですが記事内のスクリプトおよびサンプルファイルから
    再度ご確認いただければと思います。

    よろしくお願いします。

  • tone | 2016.07.29 9:33

    はじめまして、いつも勉強させていただいております。
    質問がございまして、コメントさせていただきます。

    メニューを上部で固定にさせたいのですが、
    追記のコードを教えていただけますでしょうか??

    お手数をおかけいたしますが、よろしくお願いいたします。

  • BlackFlag | 2016.07.31 1:11

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

    メニューの上部固定はスクリプトから指定するのではなく
    CSSのみで対応させることが可能かと思いますので
    メニュー全体を囲っている「#rwdMenuWrap」に対して
    「position:fixed」などのプロパティを追加するなどして
    調整いただければと思います

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

  • kyon | 2016.09.09 14:27

    はじめまして。

    responsiveでシンプルなメニューを探していてこちらにたどり着きました。
    メニューを上部ではなく、ロゴマークなど並べてから配置したいのですが、
    その場合のコードを教えていただけますか。

    ちょうど一つ前の質問の回答
    >メニュー全体を囲っている「#rwdMenuWrap」に対して
    >「position:fixed」などのプロパティを追加するなどして
    を参考にpositionをいじってみたりhtmlのコード箇所を移動させてみたりしたのですが
    うまくできずこちらに書き込みさせて頂きました。

    すみませんがどうぞよろしくお願い致します。

  • BlackFlag | 2016.09.11 11:07

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

    実装されようとしている形状が不明なのでなんとも言えないのですが
    スクリプト自体には影響しないと思われますので
    メニュー全体を囲っている「#rwdMenuWrap」に対して
    CSSでwidthで幅を指定したり、marginで位置を調整したりして
    調整をしてみていただければと思います。

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

  • shiho | 2016.10.29 13:15

    はじめまして。
    説明がわかりやすく丁寧で、初心者の私も理解しやすく、
    いつも参考にさせていただいています。ありがとうございます。

    初歩的な質問かもしれませんがお答えいただけると助かります。

    こちらの各メニューへリンクすると、
    ・他のhtmlを指定→移動する
    ・同ページ内のアンカーリンクを指定(#aaa)→移動しない
    (メニューをクリックしても文字の色が変化するだけで
    ページが移動しない)
    ・同ページの名称+アンカーリンク(index.html#aaa)→移動しない
    ・URLから指定(http://www.aaa/index.html#aaa)→移動する
    という状態です。

    スクリプト内を変更しないと同ページ内のアンカーリンクは
    移動できませんでしょうか。

    ちなみに、PC画面サイズ(スイッチポイントサイズ以上)では、
    同ページ内のアンカーリンクも正しく移動するため、
    htmlの入力ミスというわけではなさそうです。

    ご指南ください。。

  • BlackFlag | 2016.10.29 19:33

    >shihoさん
    コメントありがとうございます。
    当記事のレスポンシブメニューをご活用いただいている様で
    嬉しく思っております。

    ご質問いただきました件についてですが
    実装されているページを拝見させていただかないと何とも言えないのですが、
    おそらく当記事のスクリプトと合わせてスムーススクロールのような
    スクリプトを実装されているものだと思われますが
    その動作がページロード時のみの状態を見て
    実行されているものだと考えられます。

    スムーススクロールのクリックイベントを
    「click()」メソッドではなく「on()」メソッドに変更するか、
    当記事のサンプルスクリプトの24行目と25行目の間に
    スムーススクロールのスクリプトを再度記載しておく、
    といったことで解消できるのではないかと思っております。

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

  • shiho | 2016.10.31 9:51

    早々にご回答いただきありがとうございました!

    おっしゃるように、スムーズスクロール.jsを同時に使用しています。
    また、メイン画像部分にスライドして連続する写真を動かすinfiniteslide.js、jquery.pause.min.js、jquery/1.8/jquery.min.jsを使用しています。

    試験的に、このナビゲーション用のスクリプト以外の全てのスクリプトを削除してみましたが、やはり同ページ内のアンカーリンクには移動しませんでした。
    (厳密に言うと、PCでは移動せず、iphoneですと30秒後に不適当な場所に移動したりしなかったり、不適切な動作をしたため再度読み込みました、と表示される現象がおきます)

    何度もお伺いしずうずうしさ甚だしいのですが、ご検討いただけると幸いです。

  • BlackFlag | 2016.11.02 1:44

    >shihoさん
    当記事のサンプルファイルをそのまま使用しても
    その様な現象になっているのでしょうか。

    試しにこちらで当記事のスクリプトにページ内リンクを実装した
    パターンを作ってみましたが、その様な事象は見られませんでした。
    https://black-flag.net/devel/jQueryResponsiveMenuAccordion/jQueryResponsiveMenuAccordionScroll/

    サンプルファイルはこちらからダウンロードもできますので
    スクリプト構成と併せて確認してみていただければと思います。
    https://black-flag.net/devel/jQueryResponsiveMenuAccordion/jQueryResponsiveMenuAccordionScroll.zip

    よろしくお願いします。

  • shiho | 2016.11.02 15:01

    ご丁寧にありがとうございました!!
    こちらで大丈夫でした!

    利用させていただきます。。
    早々にご対応いただきありがとうございます。。

  • haru | 2017.09.21 17:27

    BlackFlag様

    以前より大変参考にさせていただいております。
    こちらのメニューなんですが多階層にしようとしましたがどうもうまくいきません。
    お時間に余裕がある時で大丈夫ですので何か良い方法がありましたらご教授いただければと思います。

    よろしくお願い致します。

  • BlackFlag | 2017.09.30 10:36

    >haruさん
    コメントありがとうございます。
    当記事のレスポンシブメニューをご活用いただいている様で
    嬉しく思っております。

    ご質問いただきました多階層についてですが
    ハンバーガーメニュー展開後、
    メニューリストをアコーディオンで開閉する動作にするということでしょうか。

    その場合、当スクリプトでは直接対応しておりませんが
    PCレイアウト時に使用しているメニューのHTMLソースを
    そのままハンバーガーメニューのリストに組み込まれるようにしておりますので
    スクリプトの21行目以降のハンバーガーメニューボタンクリック後に
    アコーディオン動作を実行させるようにスクリプトを追記すれば実装できるかと思います。

    ハンバーガーメニューで表示されるリストは
    「#rwdMenuWrap」のIDで囲われることになりますので
    CSSで適宜IDを継承して指定をすることになります。

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

  • kasumi | 2017.12.29 20:24

    初めまして。
    初心者の私にも非常にわかりやすく、いつも参考にさせていただいております。

    質問が

  • kasumi | 2017.12.29 20:27

    すみません途中で送信されてしましました。
    初めまして。
    初心者の私にも非常にわかりやすく、いつも参考にさせていただいております。

    質問がありまして今回投稿させていただきました。
    「switchBtn」を押すと左からメニューが出てくると思うのですが、右側のコンテンツがグレーアウトされ、クリックできなくなっていると思います。

    こちら通常通りクリックを可能にするには、どのようにすればよろしいでしょうか?
    お手数ですが、ご回答よろしくお願いいたします。

  • BlackFlag | 2018.01.14 11:22

    >kasumiさん
    コメントありがとうございます。
    当ブログのレスポンシブメニューをご活用いただいている様で
    うれしく思っております。

    ご質問いただいた件についてですが
    おそらくこの記事ではなく、別記事の
    ————————————————–
    ・jQueryでレスポンシブメニューを横スライドタイプでシンプルに実装する方法
    https://black-flag.net/jquery/20160323-5902.html
    ————————————————–
    こちらの記事だと思われますがよろしいでしょうか。

    グレーアウトの部分は「#menuOverlay」で制御していますので
    手っ取り早いやり方としてはCSSの「#menuOverlay」の
    「display:none;」プロパティに「!important」を付けて
    「display:none!important;」とすることで可能になるのではないかと思います。

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







コメント内容

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

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