JavaScript入門: クリックイベントで学ぶハンバーガーメニューの作り方

  • URLをコピーしました!

ウェブサイトでよく見かける 3本線のアイコン= ハンバーガーメニュー。スマホサイトやタブレットなど、画面が小さいデバイスで使われます。ここでは、HTML/CSS/JavaScriptを使って段階的にハンバーガーメニューを作成し、サイトに設置できるように練習してみましょう

目次

ハンバーガーメニューとは?

ハンバーガーメニューは、画面上に収まりきらないメニューをコンパクトにまとめ、アイコンをクリックすると 「メニューが表示される仕組み」 です。スマホサイトでは欠かせないデザインのひとつで、多くのウェブサイトに採用されています。動き的には、

  • ☰ このアイコンをタップすると、画面の端からスライドしてメニューが現れる
  • メニューを閉じるときは、もう一度アイコンをクリックするか、画面外をタップする

となっており、限られたスペースを有効活用 しつつ、直感的に操作できるのがポイントです。

ステップ1: 基本仕様 クリックイベント

ハンバーガーアイコンをクリックするとメニューが表示されるシンプルな機能です。

See the Pen ハンバーガーメニュー01 by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.

JavaScriptコード

const hamburger = document.querySelector('.hamburger');
const menu = document.querySelector('.menu');
  1. const
    • 定数(変更できない変数)を定義するためのキーワードです。
    • ここでは、hamburger という名前の変数にハンバーガーアイコン(.hamburger)の要素を取得して代入しています。同様に、menu という名前の変数にはメニュー(.menu)の要素を取得しています。
    • constを使うことで、「この変数は他で変更されない」となります。
  2. document.querySelector()
    • HTMLから指定したセレクター(クラス名やIDなど)を使って要素を取得するメソッド
    • '.hamburger' は、HTML内のクラス名が hamburger の要素を取得しています。同様に '.menu' はクラス名が menu の要素を取得します。
hamburger.addEventListener('click', () => {
  menu.classList.toggle('active');
});
  1. addEventListener
    • ハンバーガーアイコン(hamburger)に「クリックされたときの動作」を追加しています。
    • 第一引数の 'click' は、クリックイベントを指定しています。
    • 第二引数の () => { ... } は、クリックされたときに実行する関数(イベントハンドラ)を記述しています。
  2. アロー関数 () => { ... }
    • 通常の関数(function)の代わりに、アロー関数を使うことでコードが簡潔になります。
    • このアロー関数の中に、クリックされたときに実行する処理が書かれています。
  3. menu.classList.toggle('active')
    • menu(メニュー)のクラスリスト(classList)に対して、toggle()メソッドを使用しています。
    • toggle('active') は、menuactive クラスが付いていなければ追加し、付いていれば削除するという動きをします。
    • この操作によって、メニューの表示・非表示が切り替わる仕組みになります。

ステップ2: アニメーションを追加

ステップ1では、クリックすると、ぱ!と出てくるので、メニューが右から左にスムーズにスライドインするようにし、背景に色などをつけた、CSSでアニメーションを追加してみましょう。

See the Pen ハンバーガーメニュー02 by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.

CSSコード

.menu {
  transform: translateX(100%);
  transition: transform 0.5s ease;
  background-color: #ddd;
  position: fixed;
  top: 0;
  right: 0;
  width:50%;
  height: 100%;
}

各プロパティの解説

  1. transform: translateX(100%);
    • メニュー全体を画面右外に移動しています。100% は、要素の幅の100%分右に移動させるという意味です。左だったら-100%になります。
    • メニューが表示されていない状態では画面内に見えません。
  2. transition: transform 0.5s ease;
    • アニメーション効果を指定しています。transform の変更が 0.5秒かけてスムーズに実行されます。ease は加速・減速を滑らかにする効果です。
  3. background-color: #ddd;
    • メニュー全体の背景色を淡いグレー(#ddd)に設定しています。
  4. position: fixed;
    • メニューを画面全体に対して固定します。これにより、画面をスクロールしてもメニューは固定された位置に表示され続けます。
  5. top: 0;
    • メニューを画面の上端に配置します。
  6. right: 0;
    • メニューを画面の右端に配置します。position: fixed; と組み合わせて動作します。
  7. width: 50%
    • メニューの幅を50%に固定しています。必要に応じて好みのサイズに調整できます。
  8. height: 100%;
    • メニューの高さを画面全体(100%)に設定しています。
.menu.active {
  transform: translateX(0);
}

.menu.active の解説

  1. transform: translateX(0);
    • メニューを画面内にスライド表示させます。
    • active クラスが追加されることで、transform の値が translateX(100%) から translateX(0) に変わり、アニメーション効果でスライド表示されます。

ステップ3: 外をクリックしたら閉じる機能を追加

メニューが表示されている時、ハンバーガーボタンのみクリックしないと閉じないと言うのは、ユーザにとってとても不親切です。ボタン以外、メニュー内以外をクリックすると閉じるようにJavaScriptに追加します。

See the Pen ハンバーガーメニュー03 by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.

const hamburger = document.querySelector('.hamburger');
const menu = document.querySelector('.menu');

// ハンバーガーアイコンのクリックイベント
hamburger.addEventListener('click', () => {
  menu.classList.toggle('active');
});

// ボタン以外をクリックした場合の閉じる処理
document.addEventListener('click', (e) => {
  if (!menu.contains(e.target) && !hamburger.contains(e.target)) {
    menu.classList.remove('active');
  }
});

document.addEventListener('click', (e) => { ... })

  • document.addEventListener
    • ドキュメント全体にクリックイベントを登録します。この場合、どこをクリックしてもこのイベントが発動します。
    • 第一引数 'click' は「クリックしたときに発動するイベント」を指定しています。
    • 第二引数 (e) => { ... } は、イベントが発生したときに実行する処理(イベントハンドラ)を記述する部分です。
  • (e) =>(アロー関数)
    • ここでの e は「イベントオブジェクト」と呼ばれるものです。
    • イベントオブジェクトには、「どこをクリックしたか」「クリックされた要素は何か」といった情報が含まれています。
    • たとえば、e.target は、ユーザーがクリックした実際のHTML要素を指します。

if (!menu.contains(e.target) && !hamburger.contains(e.target))

  • e.target
    • ユーザーがクリックした要素を指します。
    • たとえば、メニュー内のリンクをクリックした場合は、そのリンク(<a>要素)が e.target となります。
  • menu.contains(e.target)
    • menu.contains() は、クリックされた要素(e.targetmenu の中に含まれているかを確認します。
    • 含まれていれば true、含まれていなければ false を返します。
  • hamburger.contains(e.target)
    • 同様に、クリックされた要素(e.target)が hamburger の中に含まれているかを確認します。
  • if (!menu.contains(e.target) && !hamburger.contains(e.target))
    • ! は「否定」を表す記号です
    • この条件は、「クリックされた要素がメニューやハンバーガーアイコンの中に 含まれていない場合」を意味します。

menu.classList.remove('active');

  • 条件が成立した場合(つまり、メニューやアイコン以外の場所をクリックした場合)、menu 要素から active クラスを削除(remove)します。
  • active クラスがなくなると、メニューが非表示になります(CSStransformtranslateX を使用して非表示状態に設定しているため)。

ステップ4: レスポンシブ対応

ハンバーガーメニューは、スマホなどの小さい画面向けに使われることが多いです。PC画面では常にメニューを表示し、スマホやタブレット画面だけでハンバーガーメニューを使用する形にします。ここで追加されるのはCSSです。

See the Pen ハンバーガーメニュー04 by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.

/* ハンバーガーメニューアイコンの基本スタイル */
.hamburger {
  font-size: 32px;
  cursor: pointer;
  display: block; /* SP版の初期状態では表示 */
}

/* メニューの基本スタイル */
.menu {
  transform: translateX(100%);
  transition: transform 0.5s ease;
  background-color: #ddd;
  position: fixed;
  top: 0;
  right: 0;
  width: 50%;
  height: 100%;
}

/* メニューが表示される時のスタイル */
.menu.active {
  transform: translateX(0);
}

/* PC版のスタイル タブレット以上 */
@media (min-width: 768px) {
  .hamburger {
    display: none; /* ハンバーガーアイコンを非表示 */
  }

  .menu {
    transform: none; /* トランスフォームを無効化 */
    position: static; /* 固定表示を解除 */
    display: flex; /* 通常の横並びメニュー */
    background-color: transparent; /* 背景を透明に */
    height: auto; /* 高さを自動調整 */
  }

  .menu ul {
    display: flex; /* メニュー項目を横並び */
    gap: 20px; /* 項目間の間隔 */
  }

  .menu li {
    list-style: none; /* リストのスタイルを削除 */
  }

  .menu a {
    text-decoration: none; /* 下線を削除 */
    color: #000; /* テキスト色を設定 */
    font-size: 16px; /* フォントサイズ */
  }
}
  • @media ルール
    • 画面幅が 768px 以上の場合に適用されるスタイルを指定。
    • 一般的にタブレット以上のサイズを想定。
  • .hamburger { display: none; }
    • PC画面では、ハンバーガーアイコンを非表示にして、常にメニューを表示します。
  • .menu { transform: none; position: static; }
    • トランスフォームと固定位置を解除し、通常のフロー(static)で表示。
  • .menu ul { display: flex; gap: 20px; }
    • メニュー項目を横並びにし、項目間に 20px の余白を追加。
  • .menu a { text-decoration: none; color: #000; }
    • リンクのスタイルをシンプルにし、読みやすく。

ステップ5: アクセシビリティ対応

アクセシビリティ対応を行うことで、キーボード操作やスクリーンリーダーでもハンバーガーメニューを正しく利用できるようにします。これにより、より多くのユーザーがメニューを使いやすくなります。

See the Pen ハンバーガーメニュー05 by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.

HTMLの解説

<div class="hamburger" aria-expanded="false" role="button" tabindex="0">
  ☰
</div>
<nav class="menu" aria-hidden="true">
  <ul>
    <li><a href="#home">Home</a></li>
    <li><a href="#about">About</a></li>
    <li><a href="#contact">Contact</a></li>
  </ul>
</nav>
  1. aria-expanded="false"
    • ハンバーガーメニューが開いている状態かどうかを示します。
    • false: メニューが閉じている。
    • true: メニューが開いている。
  2. role="button"
    • ハンバーガーアイコンが「ボタン」であることをスクリーンリーダーに伝えます。
  3. tabindex="0"
    • ハンバーガーアイコンをキーボードのタブキーでフォーカス可能にします。
  4. aria-hidden="true"
    • メニューの表示状態が非表示であることを示します。
    • true: 非表示。
    • false: 表示。

CSSの解説

.hamburger {
  font-size: 32px;
  cursor: pointer;
  display: block;
  z-index: 1000; /* メニューより前面に配置 */
}

.menu {
  transform: translateX(100%);
  transition: transform 0.5s ease, visibility 0.5s ease;
  background-color: #ddd;
  position: fixed;
  top: 0;
  right: 0;
  width: 250px;
  height: 100%;
  z-index: 999;
  visibility: hidden; /* 初期状態で非表示 */
}
  1. transform: translateX(100%);
    • メニューを画面の右外に隠します。
  2. transition: transform 0.5s ease, visibility 0.5s ease;
    • transformによるスライドアニメーションと、visibilityの切り替えにアニメーションを適用。開く時のアニメーションと閉じる時のアニメーション。
  3. visibility: hidden;
    • 初期状態でメニューを視覚的に隠します。

メニューが表示されたとき

.menu.active {
  transform: translateX(0);
  visibility: visible;
}
  1. transform: translateX(0);
    • メニューを画面内にスライドインします。
  2. visibility: visible;
    • メニューを視覚的に表示します。

レスポンシブ対応(PC画面)

@media (min-width: 768px) {
  .hamburger {
    display: none;
  }

  .menu {
    transform: none;
    position: static;
    display: flex;
    background-color: transparent;
    height: auto;
    visibility: visible;
  }

  .menu ul {
    display: flex;
    gap: 20px;
  }
}
  1. PC画面での動作
    • ハンバーガーアイコンは非表示。
    • メニューは常時横並びで表示されます。
  2. transform: none;
    • スライドアニメーションを解除。

JavaScriptの解説

hamburger.addEventListener('click', () => {
  const isExpanded = hamburger.getAttribute('aria-expanded') === 'true';

  // aria属性の更新
  hamburger.setAttribute('aria-expanded', !isExpanded);
  menu.setAttribute('aria-hidden', isExpanded ? 'true' : 'false');

  // メニュー表示の切り替え
  menu.classList.toggle('active');
});
  1. aria-expandedの更新
    • 現在の状態を確認し、trueまたはfalseを切り替えます。
  2. menu.classList.toggle('active')
    • メニューのactiveクラスを切り替え、表示・非表示を制御。

メニュー外をクリックした場合の閉じる処理

document.addEventListener('click', (e) => {
  if (
    !menu.contains(e.target) &&
    !hamburger.contains(e.target) &&
    menu.classList.contains('active')
  ) {
    // クラスを削除して閉じる
    menu.classList.remove('active');
    hamburger.setAttribute('aria-expanded', 'false');
    menu.setAttribute('aria-hidden', 'true');

    // アニメーションのため少し遅延して visibility を調整
    setTimeout(() => {
      if (!menu.classList.contains('active')) {
        menu.style.visibility = 'hidden';
      }
    }, 500); // アニメーションの時間に合わせる
  }
});
  1. !menu.contains(e.target)
    • クリックされた要素がメニュー内に含まれていないか確認します。
  2. menu.classList.remove('active')
    • メニューを閉じるためにactiveクラスを削除します。
  3. setTimeout
    • アニメーションの時間(500ms)に合わせて、閉じた後にvisibility: hidden;を適用。

ステップ6: CSSで作成する三本線とクリックで「×」に変わる補足

三本線のアイコンではなく、CSSを使ってハンバーガーアイコンが作れれば、クリックした時に×アイコンに変化するなども可能です。以下は、三本線用の線を描画するための<span>を3つ用意し、三本線をCSSで描画し、クリック時に「×」に変わるアニメーションをCSSで設定します。

See the Pen ハンバーガー by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.

HTML

<div class="hamburger">
  <span></span>
  <span></span>
  <span></span>
</div>
<nav class="menu">
  <ul>
    <li><a href="#home">Home</a></li>
    <li><a href="#about">About</a></li>
    <li><a href="#contact">Contact</a></li>
  </ul>
</nav>

CSS

/* ハンバーガーアイコンのスタイル */
.hamburger {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  width: 30px; /* 横幅 */
  height: 20px; /* 全体の高さ */
  cursor: pointer;
  z-index: 1000;
  position: relative;
}

/* 線のスタイル */
.hamburger span {
  display: block;
  height: 3px; /* 線の太さ */
  width: 100%;
  background-color: #000; /* 線の色 */
  border-radius: 2px; /* 少し角を丸める */
  transition: all 0.3s ease; /* アニメーション */
}

/* メニューのスタイル */
.menu {
  transform: translateX(100%);
  transition: transform 0.5s ease;
  background-color: #ddd;
  position: fixed;
  top: 0;
  right: 0;
  width: 250px;
  height: 100%;
  z-index: 999;
}

/* メニューが開いたときの状態 */
.menu.active {
  transform: translateX(0);
}

/* ハンバーガーがアクティブになったとき(×に変化) */
.hamburger.active span:nth-child(1) {
  transform: translateY(9px) rotate(45deg);
}

.hamburger.active span:nth-child(2) {
  opacity: 0; /* 真ん中の線を非表示 */
}

.hamburger.active span:nth-child(3) {
  transform: translateY(-9px) rotate(-45deg);
}

JavaScript

const hamburger = document.querySelector('.hamburger');
const menu = document.querySelector('.menu');

hamburger.addEventListener('click', () => {
  hamburger.classList.toggle('active');
  menu.classList.toggle('active');
});

ハンバーガーメニューは、シンプルながら多くの技術が詰まっています。ぜひ練習して、JavaScriptの基本的な使い方やウェブサイトの動的な動きを追加してみてください!

よかったらシェアしてね!
  • URLをコピーしました!
目次