ハンバーガーメニュー(三本線のアイコン)は、スマホサイトの定番ナビゲーションです。アイコンをタップするとメニューが開く仕組みを、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 で開閉状態と対象を示します。
<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 時に回転・透過させて「×」に変化させます。
.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 を更新し、スクリーンリーダーにも開閉を伝えます。
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キーを押したときに閉じると親切です。
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で閉じたらボタンへフォーカスを戻すと、キーボードだけでも快適に操作できます。
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 で出し分けます。
/* スマホ(〜767px):ハンバーガーを表示、メニューは折りたたみ */
.hamburger { display: flex; }
/* PC(768px〜):ハンバーガーを隠し、メニューを横並びで常時表示 */
@media (min-width: 768px) {
.hamburger { display: none; }
.nav-menu { display: block; } /* 常に表示 */
.nav-menu ul { display: flex; gap: 20px; }
}
prefers-reduced-motion でtransition を切ると親切です。@media (prefers-reduced-motion: reduce) { .hamburger span { transition: none; } } を加えましょう。よくある質問(FAQ)
<button>)の click イベントで、ナビゲーションメニューのclassList.toggle("open") を呼んで開閉します。CSSで .open 時のスタイル(display や transform)を定義します。document の click イベントを監視し、クリックされた要素がメニューやボタンに含まれない(!menu.contains(event.target))場合に閉じます。ボタン側では event.stopPropagation() で誤作動を防ぎます。<button> で作り、aria-expanded・aria-controls を設定して開閉時に aria-expanded を更新します。Escape キーで閉じられるようにするのも重要です。<span> に transition を設定し、.open 時に1本目・3本目を rotate で交差させ、2本目を opacity: 0 で消すと「×」になります。@media で出し分けます。狭い画面では .hamburger を表示してメニューを折りたたみ、@media (min-width: 768px) で .hamburger { display: none; } とし、メニューを横並びで常時表示します。まとめ
ハンバーガーメニューは、アイコンを <button> で作り、クリックで classList.toggle("open") するのが基本です。CSSで .open 時の表示と、3本線→×のアニメーションを定義します。
使いやすくするには、aria-expanded の更新・メニュー外クリック・Escapeで閉じる・開閉時のフォーカス移動を加えましょう。実際の運用では @media でスマホだけハンバーガーを表示し、PCでは通常メニューを見せるのが定番です。これでアクセシブルで快適なナビゲーションになります。
