follow us in feedly
JavaScriptCSS

JavaScriptでシンプルなスマホ用メニューを実装

スマートフォンサイトでよく見るハンバーガーアイコンとメニューを実装してみます。使用するのは簡単なJavaScriptのみで特にプラグインは使用しません。カスタマイズがし易いようにわかりやすくシンプルな形で作ってみたいと思います。

2019年6月16日

スマホ用メニューの完成イメージ

ハンバーガーアイコンをクリックするとメニューが開きます。アイコンは×印に変わりMENUの文字がCLOSEになります。よくある一般的なスマートフォン用のメニューです。これを簡単なJavaScriptのみで実装します。DEMO画面のようにメニュー1からメニュー14までタイミングを少しずつずらしながら左からスライドして出てくるようにします。
DEMO画面はこちら

スマートフォン用メニュー

ハンバーガーアイコンのhtml・CSS

横棒を表現する3つのspan要素とMENUの文字を入れる4つ目のspan要素で構成します。

ハンバーガーアイコンのhtml

<div id="hamburger">
  <span></span>
  <span></span>
  <span></span>
  <span id="txt">MENU</span>
</div>

ハンバーガーアイコンのCSS

span要素はいずれも絶対位置でtopからの位置を少しずつずらして配置します。左右中央に来るようにleft: 50%; transform: translateX(-50%);を指定しておきます。

#hamburger { position: fixed; display: inline-block; width: 50px; height: 50px; right: 0; background: #544969; cursor: pointer;}
#hamburger span { position: absolute; left: 50%; transform: translateX(-50%); transition: all .3s ease-out;}
#hamburger span:nth-of-type(1) { top: 10px; width: 26px; height: 2px; background: #fff;}
#hamburger span:nth-of-type(2) { top: 17px; width: 26px; height: 2px; background: #fff;}
#hamburger span:nth-of-type(3) { top: 24px; width: 26px; height: 2px; background: #fff;}
#hamburger span:nth-of-type(4) { top: 29px; font-size: 9px; color: #fff;}

ハンバーガーアイコンがクリックされたらactiveというクラスが付くようにJavaScriptで設定しますが、そのactiveが付いた状態を記述しておきます。上下の棒は45度回転させ、中央の棒は見えなくします。MENUからCLOSEへの書き換えはJavaScriptでおこないます。

#hamburger.active span:nth-of-type(1) { top:18px; transform: translateX(-50%) translateY(-50%) rotate(-45deg);}
#hamburger.active span:nth-of-type(2) { opacity: 0;}
#hamburger.active span:nth-of-type(3) { top:18px; transform: translateX(-50%) translateY(-50%) rotate(45deg);}

メニュー部分のhtml・CSS

メニュー部分のhtml

メニュー部分の記述は至ってシンプルです。ここではとりあえず14個のメニューが並ぶように記述しておきます。aタグはここでは省略します。

<nav>
  <ul>
    <li class="menu">メニュー1</li>
    <li class="menu">メニュー2</li>
    <li class="menu">メニュー3</li>
    <li class="menu">メニュー4</li>
    <li class="menu">メニュー5</li>
    <li class="menu">メニュー6</li>
    <li class="menu">メニュー7</li>
    <li class="menu">メニュー8</li>
    <li class="menu">メニュー9</li>
    <li class="menu">メニュー10</li>
    <li class="menu">メニュー11</li>
    <li class="menu">メニュー12</li>
    <li class="menu">メニュー13</li>
    <li class="menu">メニュー14</li>
  </ul>
</nav>

メニュー部分のCSS

メニュー全体を表すnav要素の記述です。top: 50px;としているのはヘッダー部分の高さ分、メニューの表示位置を下げるためです。overflow: auto;とすることでメニューの項目が多くて画面に入りきらなかったときにスクロールできるようにします。初期状態ではleft: -100%;で画面左に避けておき、ハンバーガーアイコンがクリックされたらleft: 0;で画面を覆うように表示します。

nav { position: fixed; top: 50px; left: -100%; width: 100%; height: 100%; background: #eee; overflow: auto; -webkit-overflow-scrolling: touch;}
#hamburger.active + nav { left: 0;}

先ほどnav要素をヘッダーの高さ分、位置を下げましたのでこのままではメニューの一番下50px分が欠けてしまいますので、ul要素にpadding-bottom: 50px;を指定して補正します。各li要素には疑似要素を使用してメニューらしく矢印を表示しました。

nav ul { padding-bottom: 50px;}
nav ul li { list-style: none; border-bottom: 1px solid #ddd; position: relative; line-height: 50px; font-size: 14px; padding: 0 20px;}
nav ul li:first-of-type { border-top: 1px solid #ccc;}
nav ul li:before { position: absolute; content:"\f105"; font-family: FontAwesome; left: 90%; top: 0; font-size: 14px;}

メニューの項目が出現するときに左から少しスライドして表示されるようにしますので、初期状態ではtransform: translateX(-30px);で30px左にずらして透明にしておきます。ハンバーガーアイコンがクリックされたらtransformを解除しopacityも1に変更します。

nav ul li { transform: translateX(-30px); opacity: 0; transition: all .3s ease-out;}
#hamburger.active + nav ul li { transform: none; opacity: 1;}

これで左から少しスライドしながら出現するようになりますが、項目が全て同時に出てきてしまうので上から少しずつタイミングをずらして出てくるようにします。transition-delayでli要素に遅延をかけますが、項目が増減するたびに修正するのも手間なので、この部分はJavaScriptで動的に記述するようにします。

nav ul li:nth-of-type(1) { transition-delay: 0.05s;}
nav ul li:nth-of-type(2) { transition-delay: 0.10s;}
nav ul li:nth-of-type(3) { transition-delay: 0.15s;}
nav ul li:nth-of-type(4) { transition-delay: 0.20s;}
・
・
・

JavaScriptの実装

CSS記述の動的出力

まずは先ほどのCSSの記述を動的に出力してみます。2行目でli要素(menu)の個数を取得しwhile文で繰り返し処理していきます。これで前述のようなCSSの記述が出力されます。

{
  const len = document.getElementsByClassName('menu').length;
  let num = 1;
  let nav = '';

  while(num < len + 1) {
    nav += 'nav ul li:nth-of-type(' + num + ') { transition-delay: ' + (0.05 * num).toFixed(2) + 's;}\n';
    // nav += `nav ul li:nth-of-type(${num}) { transition-delay: ${(0.05 * num).toFixed(2)}s; }\n`;
    num++;
  }

  document.querySelector('style').innerHTML = nav;
}

※コメントアウトはテンプレートリテラルを使用した書き方
テンプレート文字列 – JavaScript | MDN

クリックイベントの設定

ハンバーガーアイコンへのクリックイベントの設定は以下のようになります。内容は#hamburgerに対するactiveクラスの付与・削除と#txtに対する文字の書き換えです。

{
const hamburger = document.getElementById('hamburger');
const txt = document.getElementById('txt')

hamburger.addEventListener('click', function() {

		hamburger.classList.toggle('active');

		if(hamburger.classList.contains('active')) {
					txt.textContent = 'CLOSE';
			} else {
					txt.textContent = 'MENU';
		}

});
}

以上で「JavaScriptでシンプルなスマホ用メニューを実装」の解説を終わります。

このエントリーをはてなブックマークに追加