タップで開閉するメニュー(2段階)

タップ(クリック)で開閉するメニュー - Webデザインの日々日記の応用で2段のメニューを作ったのでメモ。

HTML

<nav class="gnav">
<div class="toggle burg">
  <span class="burg-inner"></span>
</div>
<ul class="menu1">
  <li class="toggle2"><span class="toggle2-inner">menu1</span>
    <ul class="menu2">
      <li><a href="#">menu1-child</a></li>
      <li><a href="#">menu1-child</a></li>
        ・
        ・
    </ul>
  </li>
  <li class="toggle2"><span class="toggle2-inner">menu2</span>
    <ul class="menu2">
      <li><a href="#">menu2-child</a></li>
      <li><a href="#">menu2-child</a></li>
        ・
        ・
    </ul>
  </li>
</ul>
</nav>

jQuery

<script>
jQuery(function(){
  jQuery('.toggle').click(function(){
	jQuery(this).next('.menu1').toggleClass('visible');
	jQuery(this).toggleClass('visible');
	jQuery('.toggle2').removeClass('visible2');
  });
  jQuery('.toggle2').click(function(){
	jQuery(this).toggleClass('visible2');
	jQuery(this).siblings().removeClass('visible2');
  });
});
</script>

CSS

/* メニューの配置 */
.gnav {
	position: absolute;
	top: 0;
	left: 0;
}
/* ハンバーガーボタンのデザイン */
.burg {
	display: block;
	width: 40px;
	height: 40px;
	margin: 0;
	background-color: #654d44;
	position: relative;
	border-radius: 6px;
	cursor: pointer;
}
.burg-inner, .burg-inner::before, .burg-inner::after {
	display: block;
	margin: 4px;
	width: 31px;
	height: 6px;
	background-color: #FFF3E4;
	position: absolute;
	border-radius: 6px;
}
.burg-inner {
	top: 14px;
	left: 2px;
	transition: transform 0.1s linear;
}
.burg-inner:before {
	content: " ";
	top: -16px;
	left: -4px;
	transition: width 0.1s linear;
	transition: top 0.1s linear;
}
.burg-inner:after {
	content: " ";
	left: -4px;
	bottom: -16px;
	transition: width 0.1s linear;
	transition: top 0.1s linear;
}
/* タップ時にアニメーションで矢印に変形させるギミック */
.visible .burg-inner {
	transform: rotate(360deg);
	transition: transform 0.1s linear;
}
.visible .burg-inner::before {
	transform: rotate(150deg);
	width: 25px;
	top: -10px;
	transition: width 0.1s linear;
	transition: top 0.1s linear;
}
.visible .burg-inner::after {
	transform: rotate(30deg);
	width: 25px;
	top: 1px;
	transition: width 0.1s linear;
	transition: top 0.1s linear;
}
/* メニューの開閉 1段目 左の画面外からアニメーションで引き出し表示 */
.toggle {
	position: relative;
}
.menu1 {
	position: absolute;
	width: 140px;
	left: -110%;
	top: 40px;
	text-align: left;
	background-color: #FFF;
	overflow: visible;
	transition: left 0.3s linear;
}
.menu1.visible {
	left: 0;
	transition: left 0.3s linear;
}
/* メニューの開閉 2段目 */
.toggle2 {
	box-sizing: border-box;
	display: table;
	position: relative;
	height: 40px;
	width: 100%;
	padding: 0 4px;
	border-bottom: 1px solid #654d44;
	border-left: 1px solid #654d44;
	border-right: 1px solid #654d44;
}
.toggle2-inner {
	display: table-cell;
	width: 100%;
	height: 100%;
	vertical-align: middle;
	cursor: pointer;
}
.menu2 {
	position: absolute;
	left: -110%;
	width: 100%;
	border-top: 1px solid #654d44;
}
.menu2 li {
	display: table;
	width: 100%;
	height: 40px;
}
.menu2 li>a {
	display: table-cell;
	width: 100%;
	height: 100%;
	vertical-align: middle;
	background-color: #FFF;
	border-bottom: 1px solid #654d44;
	border-left: 1px solid #654d44;
	border-right: 1px solid #654d44;
	padding: 0 4px;
	text-decoration: none;
}
.visible2 .menu2 {
	left: 140px;
	margin-top: -1px;
}

解説

第1階層メニューの表示

<div class="burg toggle">はハンバーガーボタンとなり、これがメニューを表示するスイッチとなる。
jQueryで、"toggle"クラスの要素をクリックすると、"menu1"のクラスに"visible"クラスが追加される。
"menu1"クラスは、初期状態では画面の左端より外側に配置されている(left:110%;)が、"visible"クラスが付与されると、ハンバーガーボタン直下に配置される(left:0;)。このleftの変化に対してCSSアニメーションをつけることで、画面の左側からニュッっとメニューが引き出されてくる。
この"visible"クラスの追加、削除はjQuery
jQuery('.toggle').click(function(){
jQuery(this).next('.menu1').toggleClass('visible');
}
で行っている。
この関数内の
jQuery(this).toggleClass('visible');
は、"toggle"クラスへの"visible"クラスの追加・削除を行う式で、ハンバーガーボタンの形状変化をこれで制御している。
また、
jQuery('.toggle2').removeClass('visible2');
は、ハンバーガーボタンを押したときに、第2階層の表示も消すためのものである。これがないと、第2階層まで表示した状態でハンバーガーボタンを押してメニューを引っ込めても、表示していた第2階層が残ったままになる。

第2階層メニューの表示

"menu1"直下のliには"toggle2"クラスが付与されている。"toggle2"をタップ(クリック)すると、その直下のの"menu2"クラスに"visible2"クラスが追加される。
"menu2"も"menu1"同様、初期状態では画面の左外側に配置(left:110%;)しておき、"visible2"クラスが追加されると、"menu1"の隣に並んで表示されるようにしている(left:140px;)。この"left:140px;"の140pxは、"menu1"に与えたwidth1と同じ値である。
".visible2 .menu2"の"margin-top:-1px;"は、borderの分、"menu2"が下にずれるのを補正している。


"toggle2"クラスの追加、削除は
jQuery('.toggle2').click(function(){
jQuery(this).toggleClass('visible2');
}
で行われている。これにより、"toggle2"をタップ(クリック)したときに、"visible2"が無ければそれをつけ、あれば消すという動作を行う。
この式だけでは、第1階層メニューを1回ずつタップしていくと、他の第2階層メニューが開いたままになる。他の第1階層メニュー("toggle2")をタップした時には、既に開いている第2階層メニューは閉じるようにしなければならないため、
jQuery(this).siblings().removeClass('visible2');
の式を使う。これは"toggle2"をタップした時、兄弟セレクタにある"visible2"を消す命令となっている。

その他

今回、第1階層メニューにはCSSアニメーションをつけたが、第2階層メニューにはつけていない。第2階層メニューは高さ0からニュッと縦に伸びるようにしたかったが、あまりきれいに動いてくれない(内部の文字が先に表示され、アニメーションのほうが遅れる)ため、今回はCSSアニメーションはつけなかった。