[CSS/jQuery]モバイル等(レスポンシブ対応含む)でよく使うトグルメニューの実装〜追記あり

  • スポンサーリンク

  • スポンサーリンク

モバイル等でよく使うトグルメニューの実装メモです(jQuery使用)

概要

モバイル等でよく使うトグルメニューをjQueryを利用して実現しました。
こんな感じの表示になります。
toggle

※以前、左右にスライドするメニューをsidrで実現する方法を記載しましたが([WordPress/jQuery]モバイル等でよく使うスライドメニューの実装(Sidr使用)、考え方は似ていましたが、ウインドウサイズを変化させた時の挙動に少しハマりました。

■追記
ウインドウサイズ変化させた時の挙動に関して不自然な箇所があったので改善しました。

前提条件

・ウインドウ幅が800pxより大きいと、横並びのメニュー表示
・ウインドウ幅が800px以下になると三本線メニューアイコン「」のみになります。
・その状態で、「」を押す毎に、縦並びのメニューの表示、非表示がスライドしながら切り替わります。
・ウインドウ幅を変化させると、800pxより大きいか、以下かにより(厳密にはウインドウ幅では判定せず。後述)、メニュー部分の表示、非表示も切り替わります。

HTMLソース

<div id="accordion_menu"><a href="#"><i class="fa fa-bars"></i></a></div>
<ul id="navlist">
	<li class="menulist"><a href="http://www.nakamurayuji.com/">ポータルサイト</a></li>
	<li class="menulist"><a href="http://diary.nakamurayuji.com/">日記</a></li>
	<li class="menulist"><a href="http://www.nakamurayuji.com/">Webなど</a></li>
	<li class="menulist"><a href="http://capture.nakamurayuji.com/">音楽活動</a></li>
	<li class="menulist"><a href="http://musicvideo.nakamurayuji.com/">音楽映像紹介</a></li>
</ul>

jQueryソース

<script>
$(function(){
  $("#accordion_menu").click(function(){
    $("#navlist").slideToggle();
    return false;
  });
  $(window).resize(function(){
  if ($('.menulist').css('float') == 'left') {
      $("#navlist").show();
} else {
      $("#navlist").hide();
}
  });
});
</script>

CSSソース

・スライドトグル動作に関係ある箇所のみを抜粋
・レイアウトや色などの指定は省略しています。

#accordion_menu {
	display:none;
}
#navlist {
	display:block;
}
.menulist {
	float:left;
	width:150px;
}

@media only screen and (max-width: 800px) {
#accordion_menu {
	display:block;
}
i.fa {
	font-size:2em;
}
#navlist {
	display:none;
}
.menulist {
	float:none;
	width:90%;
	margin:0 5%;
}
}

コード説明

◯HTML部分

<div id="accordion_menu"><a href="#"><i class="fa fa-bars"></i></a></div>
<ul id="navlist">
	<li class="menulist"><a href="http://www.nakamurayuji.com/">ポータルサイト</a></li>
	<li class="menulist"><a href="http://diary.nakamurayuji.com/">日記</a></li>
<!-- 略 -->
</ul>

・accordion_menuの部分;通常非表示、ウインドウ幅が小さくなると表示されます。
・「i class=”fa fa-bars”」が三本線部分の記述。この部分をクリックorタップするとjQueryが動作し、メニュー表示/非表示が切り替わります。
・navlistがメニュー部分です。ここ全体の表示を制御します。

◯jQuery部分

<script>
$(function(){
  $("#accordion_menu").click(function(){
    $("#navlist").slideToggle();
    return false;
  });
  $(window).resize(function(){
  if ($('.menulist').css('float') == 'left') {
      $("#navlist").show();
} else {
      $("#navlist").hide();
}
  });
});
</script>

・#accordion_menuを押すと、#navlist部分に対し、slideToggle()関数が動作し、メニュー表示/非表示を制御します。
・$(window).resize部分は、ウインドウ幅が変わった時に動作します。
・menulistクラス部分(つまり各メニュー項目)のfloatプロパティが、left(PC表示)であれば、メニュー部分#navlistが表示(show)され、none(モバイル表示)であれば、非表示(hide)とします。
・後半の関数がないと、モバイル状態で、三本線メニュー部分を押して、表示から再度、非表示にした状態で、ウインドウ幅を大きくしPC表示にしても、メニュー部分が非表示のままとなってしまう現象が起きてしまいます。※非表示にした段階で「ul id=”navlist” style=”display: none;”」というコードがjQueryで設定されるため。
・後半の関数は本来であればウインドウ幅が800pxより大きいか、以下かによって判定すべきなのですが、ウインドウ幅に関する関数やプロパティがいろいろあって($(window).width();やwindow.innerWidth;等)、また、ブラウザによって戻り値が変化したりで(最初、Internet Explolerで遷移時にメニューが表示されないウインドウ幅があってそれはもう…)、はまりそうだったので、参考サイト(後述する)で紹介されていた方法を真似て、ウインドウ幅によって確実に変化するCSSプロパティで判定させることにしました。

◯CSS部分

#accordion_menu {
	display:none;
}
#navlist {
	display:block;
}
.menulist {
	float:left;
	width:150px;
}

・PC表示状態なので、三本線アイコンは非表示、メニューは表示しています。
・横並びのメニューなので、float:left;を指定。

@media only screen and (max-width: 800px) {
#accordion_menu {
	display:block;
}
i.fa {
	font-size:2em;
}
#navlist {
	display:none;
}
.menulist {
	float:none;
	width:90%;
}
}

・800px以下の状態を記述しています。
・三本線アイコンを表示、メニュー部分(#navlist)は非表示です。
・三本線アイコンはawesomeフォント利用です。
・メニュー部分(menulist)を縦並びにするため、float:none;にし、幅を画面いっぱいにひろげます。

追記(2015/3/3)

・上記のjQueryで「$(window).resize」という部分を記述した意図は、「ウインドウ幅が変わった時にウインドウ幅によってメニュー部分の表示・非表示を設定する」ためだったのですが、どうも、iPhone等で、ウインドウ幅は変わらないのに、縦方向にスクロールした際に「resize」が発生してしまい、せっかく表示されたトグルメニューがすぐ非表示になってしまい使いにくい、との指摘がありました。
 ※参考:iOS 8.0でSafariでスクロールするとresizeイベントが実行される | iwb.jp
・そこで、以下の様なHTML/CSS/jQueryを変更・追記しました。

<div id="dummy_area1"></div>
<script>
$(function(){
  $("#accordion_menu").click(function(){
    $("#navlist").slideToggle();
    return false;
  });
	$(window).load(function () {
		var width1 = $(window).width();
		$("#dummy_area1").width(width1);
	});

  $(window).resize(function(){
		var win = $(window).width();
		if (win != $("#dummy_area1").width()) {
			$("#dummy_area1").width(win);
			if ($('.menulist').css('float') == 'left') {
			  $("#navlist").show();
			} else {
			  $("#navlist").hide();
			}
		}
  });
});
</script>

#dummy_area1 {
	display:none;
	width:1px;
}

追記の説明(2015/3/3)

・非表示(display:none;)のdiv要素「dummy_area1」を追加し、CSS上は「width:1px;」ですが、jQueryの「$(window).load」によりサイトがロードされた際に、ウインドウ幅を取得し、その値を「dummy_area1」の「width」に設定します。
・ウインドウがリサイズされたら、まず、「ウインドウ幅」を$(window).width();で取得、また、「dummy_area1」の「width」を取得し、異なっていたら、「menulist」の「float」プロパティが「left」かそれ以外かで、メニュー部分「#navlist」の表示・非表示を設定します。その際、$(window).width();で取得された値を「dummy_area1」の「width」に再設定しておきます。
・これでiPhoneでの縦スクロールでも、いったん表示したメニュー部分はそのままです。
※おそらく、他にも色々方法はあったり、もしかすると、このあたり対策されたjQueryプラグイン等もあるかもしれませんが、一つの解決方法として記しておきました。

適用サイト

トグルメニューの例 http://www.nakamurayuji.com/demo/menu_toggle.html

参考サイト(本当に有難うございます!)

JavaScript – media query のスクリーン幅と jQuery(window).width() の関係 – Qiita
 →本当に助けられました!
レスポンシブWebデザインに対応したメニューの作り方【追記あり】|Webpark
 →基本的にこちらを参考にさせて頂きました。ウインドウ幅の判定部分は上述のとおりなのですが、この記事にも本当に助けられました。

最後に

・Chromeでデバッグし、動作OKだったのに、($(window).width();を使用していたのですが、)Internet Explorerでメニューが消えた時は焦ったと同時にまたIE問題か!とも思いましたが、ウインドウ幅に関する理解不足によるものでした。とりあえずはまりたくなかったので、別のCSSプロパティで判断しましたが、ウインドウ幅周りの関数も理解を進めたいと思います。
/////


  • スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA