【JavaScript】ハンバーガーメニューの作り方

ハンバーガーメニュー(三本線のアイコン)は、スマホサイトの定番ナビゲーションです。アイコンをタップするとメニューが開く仕組みを、HTML・CSS・JavaScriptで作ります。

ポイントは、アイコンを <button> で作ること(キーボード操作・読み上げ対応)と、メニュー外のクリックや Escape キーで閉じる配慮です。実際に動くデモで確認しながら見ていきましょう。

この記事の結論:アイコンは <button> で作り、クリックで classList.toggle("open") を呼んで開閉します。CSSで .open 時の表示と3本線→×のアニメーションを定義。aria-expanded の更新外クリック・Escapeで閉じる処理を加えると使いやすくアクセシブルになります。
スポンサーリンク

完成イメージ(動くデモ)

↓ ボタンでメニューが開閉します(外クリック・Escapeでも閉じます):

HTMLの構造

アイコンは <button> で作ります。3本線は <span> 3つで表現し、aria-expanded / aria-controls で開閉状態と対象を示します。

HTML
<button class="hamburger" aria-expanded="false" aria-controls="nav" aria-label="メニュー">
  <span></span><span></span><span></span>
</button>

<nav id="nav" class="nav-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でスタイリングと×アニメーション

メニューは初期状態で display: none.open が付いたら表示します。3本線は .open 時に回転・透過させて「×」に変化させます。

CSS
.hamburger {
  width: 30px; height: 21px;
  display: flex; flex-direction: column; justify-content: space-between;
  background: none; border: none; cursor: pointer; padding: 0;
}
.hamburger span {
  display: block; height: 3px; background: #333;
  transition: all 0.3s ease;
}

/* 開いたとき:3本線 → × */
.hamburger.open span:nth-child(1) { transform: translateY(9px) rotate(45deg); }
.hamburger.open span:nth-child(2) { opacity: 0; }
.hamburger.open span:nth-child(3) { transform: translateY(-9px) rotate(-45deg); }

.nav-menu { display: none; }
.nav-menu.open { display: block; } /* 開いたとき表示 */

JavaScriptで開閉する(aria-expanded更新つき)

ボタンのクリックで classList.toggle("open") を呼びます。あわせて aria-expanded を更新し、スクリーンリーダーにも開閉を伝えます。

JavaScript:開閉の基本
const hamburger = document.querySelector(".hamburger");
const navMenu = document.getElementById("nav");

hamburger.addEventListener("click", () => {
  const isOpen = navMenu.classList.toggle("open");
  hamburger.classList.toggle("open", isOpen);
  hamburger.setAttribute("aria-expanded", String(isOpen));
});

クラスの操作はclassListの使い方、表示/非表示の切り替えは要素の表示/非表示を切り替える方法も参考になります。

メニュー外クリック・Escapeキーで閉じる

メニューを開いたあと、メニュー以外をクリックしたときEscapeキーを押したときに閉じると親切です。

JavaScript:外クリック・Escapeで閉じる
function closeMenu() {
  navMenu.classList.remove("open");
  hamburger.classList.remove("open");
  hamburger.setAttribute("aria-expanded", "false");
}

// メニューの外側をクリックしたら閉じる
document.addEventListener("click", (event) => {
  if (!hamburger.contains(event.target) && !navMenu.contains(event.target)) {
    closeMenu();
  }
});

// Escapeキーで閉じる
document.addEventListener("keydown", (event) => {
  if (event.key === "Escape") closeMenu();
});

ボタンのクリックがすぐに「外クリック」と判定されないよう、ボタンのハンドラ内で event.stopPropagation() を呼ぶか、判定で除外しておきます。同種のドロップダウンUIはドロップダウンメニューを作る方法も参考になります。

フォーカス管理でキーボード操作を快適に

アクセシビリティをさらに高めるなら、開いたらメニュー内の最初のリンクへフォーカスを移し、Escapeで閉じたらボタンへフォーカスを戻すと、キーボードだけでも快適に操作できます。

JavaScript:開閉時のフォーカス移動
function openMenu() {
  navMenu.classList.add("open");
  hamburger.classList.add("open");
  hamburger.setAttribute("aria-expanded", "true");
  navMenu.querySelector("a")?.focus(); // 最初のリンクへ
}

function closeMenu(returnFocus = false) {
  navMenu.classList.remove("open");
  hamburger.classList.remove("open");
  hamburger.setAttribute("aria-expanded", "false");
  if (returnFocus) hamburger.focus(); // ボタンへ戻す
}

// Escapeで閉じたときはボタンへフォーカスを戻す
document.addEventListener("keydown", (event) => {
  if (event.key === "Escape") closeMenu(true);
});

スマホだけハンバーガーを表示する(レスポンシブ)

ハンバーガーメニューは、ふつうスマホなど画面が狭いときだけ表示し、PCの広い画面では通常の横並びメニューを見せます。これは @media で出し分けます。

CSS:画面幅で出し分ける
/* スマホ(〜767px):ハンバーガーを表示、メニューは折りたたみ */
.hamburger { display: flex; }

/* PC(768px〜):ハンバーガーを隠し、メニューを横並びで常時表示 */
@media (min-width: 768px) {
  .hamburger { display: none; }
  .nav-menu { display: block; }       /* 常に表示 */
  .nav-menu ul { display: flex; gap: 20px; }
}
animationへの配慮:3本線→×の動きが苦手なユーザーのために、prefers-reduced-motiontransition を切ると親切です。@media (prefers-reduced-motion: reduce) { .hamburger span { transition: none; } } を加えましょう。

よくある質問(FAQ)

QJavaScriptでハンバーガーメニューを実装するには?
Aアイコン(<button>)の click イベントで、ナビゲーションメニューのclassList.toggle("open") を呼んで開閉します。CSSで .open 時のスタイル(displaytransform)を定義します。
Qメニューをクリック外で閉じる処理はどう実装しますか?
Adocumentclick イベントを監視し、クリックされた要素がメニューやボタンに含まれない(!menu.contains(event.target))場合に閉じます。ボタン側では event.stopPropagation() で誤作動を防ぎます。
Qハンバーガーメニューのアクセシビリティ対応は?
Aアイコンを <button> で作り、aria-expandedaria-controls を設定して開閉時に aria-expanded を更新します。Escape キーで閉じられるようにするのも重要です。
Q3本線を×印に変えるアニメーションは?
A3本の <span>transition を設定し、.open 時に1本目・3本目を rotate で交差させ、2本目を opacity: 0 で消すと「×」になります。
Qスマホのときだけハンバーガーを表示するには?
A@media で出し分けます。狭い画面では .hamburger を表示してメニューを折りたたみ、@media (min-width: 768px).hamburger { display: none; } とし、メニューを横並びで常時表示します。

まとめ

ハンバーガーメニューは、アイコンを <button> で作り、クリックで classList.toggle("open") するのが基本です。CSSで .open 時の表示と、3本線→×のアニメーションを定義します。

使いやすくするには、aria-expanded の更新メニュー外クリック・Escapeで閉じる開閉時のフォーカス移動を加えましょう。実際の運用では @mediaスマホだけハンバーガーを表示し、PCでは通常メニューを見せるのが定番です。これでアクセシブルで快適なナビゲーションになります。