FizzLearnのロゴ画像

実例で学ぶ!JavaScriptで簡単にハンバーガーメニューを作る方法

hamburger_menu

こんにちは!Webデザイナーのイワサキです。
Webサイトを訪問した時に、3本線のメニューがあるのを見たことはありませんか?
この3本線メニューのことをハンバーガーメニューといい、ナビゲーションメニューに使われるデザインの手法のひとつです。
Webサイトを構築する上で、必ず必要な実装になります。

当記事では、JavaScriptを使ったハンバーガーメニューの作り方についてやさしく解説します。

ではいってみましょう。

サンプルコードを確認

まず、サンプルコードを確認します。

<header class="header">
    <div class="header__inner">
      <h1 class="header__logo">
        <a class="header__logo--link" href="#">
          Logo
        </a>
      </h1>
      <div class="header__gnav">
        <nav class="header__nav">
          <ul class="header__list">
            <li class="header__item">
              <a class="header__item--link" href="#">Menu</a>
            </li>
            <li class="header__item">
              <a class="header__item--link" href="#">Menu</a>
            </li>
            <li class="header__item">
              <a class="header__item--link" href="#">Menu</a>
            </li>
            <li class="header__item">
              <a class="header__item--link" href="#">Menu</a>
            </li>
          </ul>
        </nav>
      </div>
      <div class="header__menu">
        <button class="header__hamburger">
          <span class="header__hamburger--border"></span>
          <span class="header__hamburger--border"></span>
          <span class="header__hamburger--border"></span>
        </button>
      </div>
    </div>
  </header>
* {
  padding: 0;
  margin: 0;
  text-decoration: none;
  list-style: none;
  color: #000;
}

.header {
  padding: 40px 64px;
  background-color: blueviolet;
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.header__logo--link {
  font-size: 40px;
  color: #fff;
}

.header__list {
  display: flex;
  align-items: center;
  column-gap: 24px;
}

.header__item--link {
  font-size: 16px;
  color: #fff;
}

.header__menu {
  display: none;
}

@media screen and (max-width: 1024px) {
  .header__gnav {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: blueviolet;
    transform: translateX(100%);
    -webkit-transform: translateX(100%);
    -moz-transform: translateX(100%);
    -ms-transform: translateX(100%);
    -o-transform: translateX(100%);
    transition: transform 0.6s;
    -webkit-transition: transform 0.6s;
    -moz-transition: transform 0.6s;
    -ms-transition: transform 0.6s;
    -o-transition: transform 0.6s;
    z-index: 98;
  }

  .header__gnav.is_open {
    transform: translateX(0);
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
  }

  .header__list {
    display: flex;
    flex-direction: column;
    row-gap: 24px;
  }

  .header__menu {
    position: relative;
    display: block;
    width: 40px;
    height: 16px;
    z-index: 99;
  }

  .header__hamburger {
    display: block;
    border: none;
    color: inherit;
    background: none;
    width: 100%;
    height: 100%;
    padding: 0;
  }

  .header__hamburger--border {
    display: block;
    width: 100%;
    height: 1px;
    background-color: #fff;
    transition: transform 0.6s;
    -webkit-transition: transform 0.6s;
    -moz-transition: transform 0.6s;
    -ms-transition: transform 0.6s;
    -o-transition: transform 0.6s;
  }

  .header__hamburger--border:nth-child(2) {
    margin-top: 8px;
  }

  .header__hamburger--border:nth-child(3) {
    margin-top: 8px;
  }

  .header__menu.is_click .header__hamburger--border:nth-child(1) {
    transform: translate(0px, 9px) rotate(45deg);
    -webkit-transform: translate(0px, 9px) rotate(45deg);
    -moz-transform: translate(0px, 9px) rotate(45deg);
    -ms-transform: translate(0px, 9px) rotate(45deg);
    -o-transform: translate(0px, 9px) rotate(45deg);
  }

  .header__menu.is_click .header__hamburger--border:nth-child(2) {
    opacity: 0;
  }

  .header__menu.is_click .header__hamburger--border:nth-child(3) {
    transform: translate(0px, -9px) rotate(-45deg);
    -webkit-transform: translate(0px, -9px) rotate(-45deg);
    -moz-transform: translate(0px, -9px) rotate(-45deg);
    -ms-transform: translate(0px, -9px) rotate(-45deg);
    -o-transform: translate(0px, -9px) rotate(-45deg);
  }
}
const ham = document.querySelector('.header__menu');
const nav = document.querySelector('.header__gnav');
const links = document.querySelectorAll('.header__item--link');

ham.addEventListener('click', function() {
  ham.classList.toggle('is_click');
  nav.classList.toggle('is_open');
});

links.forEach(function (link) {
  link.addEventListener('click', () => {
    ham.classList.remove('is_click');
    nav.classList.remove('is_open');
  });
});

HTMLの解説

ハンバーガーメニューのHTMLについて解説をします。

<header class="header">
    <div class="header__inner">
      <h1 class="header__logo">
        <a class="header__logo--link" href="#">
          Logo
        </a>
      </h1>
   <!-- ナビゲーション -->
      <div class="header__gnav">
        <nav class="header__nav">
          <ul class="header__list">
            <li class="header__item">
              <a class="header__item--link" href="#">Menu</a>
            </li>
            <li class="header__item">
              <a class="header__item--link" href="#">Menu</a>
            </li>
            <li class="header__item">
              <a class="header__item--link" href="#">Menu</a>
            </li>
            <li class="header__item">
              <a class="header__item--link" href="#">Menu</a>
            </li>
          </ul>
        </nav>
      </div>
   <!-- ナビゲーションメニュー -->
   <!-- ハンバーガーメニュー -->
      <div class="header__menu">
        <button class="header__hamburger">
          <span class="header__hamburger--border"></span>
          <span class="header__hamburger--border"></span>
          <span class="header__hamburger--border"></span>
        </button>
      </div>
   <!-- ハンバーガーメニュー -->
    </div>
  </header>

<header>タグの中にハンバーガーメニューを作成します。
ハンバーガーメニューを<button>タグで作成し、3本線を<span>タグで作成します。

CSSの解説

次に、ハンバーガーメニューのCSSについて解説します。

 /* デフォルトCSS削除 */
* {
  padding: 0;
  margin: 0;
  text-decoration: none;
  list-style: none;
  color: #000;
}

.header {
  padding: 40px 64px;
  background-color: blueviolet;
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.header__logo--link {
  font-size: 40px;
  color: #fff;
}

.header__list {
  display: flex;
  align-items: center;
  column-gap: 24px;
}

.header__item--link {
  font-size: 16px;
  color: #fff;
}

 /* PC時は非表示 */
.header__menu {
  display: none;
}

全体のデフォルトCSSを削除し、ヘッダー全体にCSSを指定します。
PC時にハンバーガーメニューが非表示になるようにdisplay: noneを指定します。

@media screen and (max-width: 1024px) {
/* この中に記述 */
}

次に、メディアクエリを使って画面サイズが1024px以下の表示を設定します。

  /* ナビゲーションメニューの全体 */
  .header__gnav {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: blueviolet;
    transform: translateX(100%);
    -webkit-transform: translateX(100%);
    -moz-transform: translateX(100%);
    -ms-transform: translateX(100%);
    -o-transform: translateX(100%);
    transition: transform 0.6s;
    -webkit-transition: transform 0.6s;
    -moz-transition: transform 0.6s;
    -ms-transition: transform 0.6s;
    -o-transition: transform 0.6s;
    z-index: 98;
  }

  /* ハンバーガーメニューををクリックした時のナビゲーションの表示 */
  .header__gnav.is_open {
    transform: translateX(0);
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
  }

  .header__list {
    display: flex;
    flex-direction: column;
    row-gap: 24px;
  }

positionプロパティを使って、ナビゲージョン全体の位置を基準の上から0px・左から0pxに指定し、transform : translateX(100%)で画面から見えない位置に配置します。

ハンバーガーメニューをクリックした時に、JavaScriptでナビゲーションメニューのheader__gnavクラスにis_openクラスを付与します。
is_openクラスが付与されたら、ナビゲーションメニューが画面に表示されるようにtransform: translateX(0)で位置を設定します。

また、クリックした時にハンバーガーメニューが隠れないように、z-indexプロパティで重なり順をコントロールします。

  /* ハンバーガーメニュー表示 ・ 横幅と高さを設定 */
  .header__menu {
    position: relative;
    display: block;
    width: 40px;
    height: 16px;
    z-index: 99;
  }

  /* buttonタグのデフォルトCSS削除 */
  .header__hamburger {
    display: block;
    border: none;
    color: inherit;
    background: none;
    width: 100%;
    height: 100%;
    padding: 0;
  }

  /* 3本線の装飾 */
  .header__hamburger--border {
    display: block;
    width: 100%;
    height: 1px;
    background-color: #fff;
    transition: transform 0.6s;
    -webkit-transition: transform 0.6s;
    -moz-transition: transform 0.6s;
    -ms-transition: transform 0.6s;
    -o-transition: transform 0.6s;
  }

  .header__hamburger--border:nth-child(2) {
    margin-top: 8px;
  }

  .header__hamburger--border:nth-child(3) {
    margin-top: 8px;
  }

  /* ハンバーガーメニューをクリックした時の表示 */
  .header__menu.is_click .header__hamburger--border:nth-child(1) {
    transform: translate(0px, 9px) rotate(45deg);
    -webkit-transform: translate(0px, 9px) rotate(45deg);
    -moz-transform: translate(0px, 9px) rotate(45deg);
    -ms-transform: translate(0px, 9px) rotate(45deg);
    -o-transform: translate(0px, 9px) rotate(45deg);
  }

  .header__menu.is_click .header__hamburger--border:nth-child(2) {
    opacity: 0;
  }

  .header__menu.is_click .header__hamburger--border:nth-child(3) {
    transform: translate(0px, -9px) rotate(-45deg);
    -webkit-transform: translate(0px, -9px) rotate(-45deg);
    -moz-transform: translate(0px, -9px) rotate(-45deg);
    -ms-transform: translate(0px, -9px) rotate(-45deg);
    -o-transform: translate(0px, -9px) rotate(-45deg);
  }

ハンバーガーメニューをdisplay: blockで表示させ、positionプロパティで重なり順を設定します。
ハンバーガーメニューをクリックした時に、ハンバーガーメニューのheader__menuクラスにis_clickクラスを付与します。
is_clickクラスを付与されたら、3本線が × になるようにCSSで調節をします。
線の位置はtranslate、角度はrotateで調節をします。

JavaScriptの解説

ハンバーガーメニューのJavaScriptについて解説します。

const ham = document.querySelector('.header__menu');
const nav = document.querySelector('.header__gnav');

ハンバーガーメニューのheader__menuクラスとナビゲーションメニューheader__gnavクラスを取得し、変数に代入します。

ham.addEventListener('click', function() {
  //ここにハンバーガーメニューをクリックした時のイベント処理を記述
});

ハンバーガーメニューをクリックした時のイベント処理を書きます。

ham.addEventListener('click', function() {
  ham.classList.toggle('is_click');
  nav.classList.toggle('is_open');
});

classList.toggle()を使用することで、指定した要素にクラス名の追加・削除の切り替え行うことができます。
ハンバーガーメニューの場合、header__menuクラスにis_clickクラスが存在すれば、is_clickクラスを削除する・is_clickクラスが存在していなければ、is_clickクラスを追加します。

const links = document.querySelectorAll('.header__item--link');

次に、ナビゲーションメニューをクリックしたらハンバーガーメニューを閉じる処理を記述します。
querySelectorAllで複数あるナビゲーションメニューのheader__item–linkクラスを取得し、変数に代入します。

links.forEach(function (link) {
  //ここに処理を記述
});

今回はナビゲーションメニューが4つあるので全て取得します。
forEach()メソッドを使うことで配列の数だけ繰り返し処理を行うことができます。

links.forEach(function (link) {
  link.addEventListener('click', () => {
    
  });

ナビゲーションメニューのリンクをクリックした時のイベント処理を記述します。
forEach()メソッドに格納されている配列「link」を使ってイベント処理を実行します。

links.forEach(function (link) {
  link.addEventListener('click', () => {
    ham.classList.remove('is_click');
    nav.classList.remove('is_open');
  });
});

removeメソッドを指定することで、クラス名を削除することができます。
ナビゲーションメニューのリンクをクリックした時に、ハンバーガーメニューのis_clickクラスを削除・ナビゲーションメニューのis_openクラスを削除することができます。
ここまで記述できたら完成!

実際に動作を確認してみましょう。

まとめ

いかがでしたか?
今回はJavaScriptを使ったハンバーガーメニューの作り方について解説しました。
CSSを調節することで様々なハンバーガーメニューを実装することができます。