「CSSだけで作るハンバーガーメニュー」JavaScript不要、チェックボックスで動く仕組みから丁寧に
「ハンバーガーメニューって、JavaScriptがないと作れないんじゃないの?」そう思っている方、多いと思います。実はCSSだけでもちゃんと動くんです。仕組みから一緒に見ていきましょう。

そもそもハンバーガーメニューって?
三本線のアイコンをタップすると、メニューがふわっと開く。スマホサイトでよく見る、あの仕組みです。アイコンの形がハンバーガー(パン・パティ・パン)に似ているから、ハンバーガーメニューと呼ばれるようになりました。かわいい名前ですよね。
このメニュー、多くの人が「JavaScriptで開いたり閉じたりするもの」と思っています。実際、現場でもJavaScriptで実装されることが多いです。でも実は、<input type="checkbox"> をうまく使うと、CSSだけでも同じ動きが作れるんです。
「JavaScriptをまだ勉強していないから、ハンバーガーメニューはまだ無理…」と思っていた方、大丈夫です。今日はCSSだけで動く方法を、ひとつずつ丁寧に見ていきましょう。仕組みがわかれば、応用もきくようになりますよ。
仕組みのキモは「チェックボックス」
CSSだけでメニューを開閉するために使うのが、<input type="checkbox"> です。チェックボックスには「チェックされている/されていない」という2つの状態がありますよね。この状態の切り替わりを、CSSの :checked 擬似クラスで拾って、メニューを表示/非表示する。これがすべての仕組みです。
「でもチェックボックスって、あの四角い箱のことでしょ? ハンバーガーアイコンと関係なくない?」と思いますよね。ここが今回いちばんおもしろいポイントです。チェックボックス本体は display: none で見えなくしておいて、代わりに <label> でハンバーガーアイコンを作るんです。label をクリックすると、紐づいたチェックボックスのオン/オフが切り替わる——HTMLの基本機能ですね。これを利用します。
身近な例で言うと、スイッチと電球の関係に似ています。チェックボックスは壁の中に隠れた配線(スイッチの本体)。ラベルは表に出ている押しやすいスイッチカバー。そしてメニューが電球です。私たちが操作するのはカバーだけ。中の配線がオン/オフを切り替え、それに反応して電球が光る。CSSのハンバーガーメニューも、これと同じ構造で動いています。
<!-- チェックボックス本体(CSSで隠す) -->
<input type="checkbox" id="menu-toggle" class="menu-checkbox">
<!-- ハンバーガーアイコン(labelで作る) -->
<label for="menu-toggle" class="menu-btn">
<span></span><span></span><span></span>
</label>
<!-- 開閉するメニュー本体 -->
<nav class="menu">
<ul>
<li><a href="#">HOME</a></li>
<li><a href="#">ABOUT</a></li>
<li><a href="#">CONTACT</a></li>
</ul>
</nav>
HTMLはこれだけです。注目してほしいのは、<label for="menu-toggle"> の for 属性。これがチェックボックスの id と一致していることで、ラベルとチェックボックスが「結びつき」ます。この結びつきがあるから、ラベルをクリックするだけでチェック状態が切り替わるんですね。
シンプル版を作ってみよう
まずは、いちばんシンプルな「クリックで開いて、もう一度クリックで閉じる」だけのメニューを作ります。アイコンの変化はあとで足すとして、ここでは開閉の動きだけに集中しましょう。
/* チェックボックスは隠す */
.menu-checkbox {
display: none;
}
/* ハンバーガーボタン(≡の文字をそのまま使う簡易版) */
.menu-btn {
font-size: 24px;
cursor: pointer;
color: #0d9488;
}
/* メニューは最初は閉じている(高さ0) */
.menu {
max-height: 0;
overflow: hidden;
transition: max-height 0.35s ease;
}
/* チェックされたら、隣にあるメニューを開く */
.menu-checkbox:checked ~ .menu {
max-height: 240px;
}
ポイントは2つあります。ひとつめは max-height を使っていること。height: auto はトランジションが効かないので、代わりに「最大の高さ」を変化させて開閉を演出します。少し裏技っぽいですが、CSSだけで開閉アニメーションをするときの定番です。
ふたつめは ~(チルダ)という記号。これは「同じ階層の、後ろにある要素」を指すセレクタで、一般兄弟結合子と呼ばれます。「.menu-checkbox がチェックされたとき、その後ろにある .menu を変える」という意味になります。難しそうな名前ですが、要は「お兄ちゃんの状態に応じて、弟の見た目を変える」というイメージで覚えてしまいましょう。
動きましたか? 動いた方、おめでとうございます! JavaScriptを1行も書いていないのに、ちゃんとメニューが開いて閉じる。これがCSSの底力です。
三本線アイコンを「×」に変身させよう
シンプル版が動いたら、次はちゃんとハンバーガーらしい「三本線アイコン」を作って、メニューを開いたときに「×」に変身させてみましょう。ここがいちばんの見せ場です。
仕組みはシンプルです。3本の <span> を縦に並べて三本線を作り、チェックされたら——上の線は45度回転して中央へ、真ん中の線は消え、下の線はマイナス45度回転して中央へ。これで「×」が完成します。
/* 3本の線を絶対配置で重ねる土台 */
.menu-btn {
width: 32px;
height: 24px;
position: relative;
cursor: pointer;
}
.menu-btn span {
position: absolute;
left: 0;
width: 100%;
height: 3px;
background: #0d9488;
border-radius: 2px;
transition: transform 0.3s, opacity 0.3s, top 0.3s;
}
.menu-btn span:nth-child(1) { top: 0; }
.menu-btn span:nth-child(2) { top: 10px; }
.menu-btn span:nth-child(3) { top: 20px; }
/* チェック時:「×」に変身 */
.menu-checkbox:checked ~ .menu-btn span:nth-child(1) {
top: 10px;
transform: rotate(45deg);
}
.menu-checkbox:checked ~ .menu-btn span:nth-child(2) {
opacity: 0;
}
.menu-checkbox:checked ~ .menu-btn span:nth-child(3) {
top: 10px;
transform: rotate(-45deg);
}
ここで使っている :nth-child(n) は、「兄弟の中で何番目か」で要素を選ぶセレクタです。:nth-child(1) は1本目の線、:nth-child(2) は2本目、というふうに指定できます。3本それぞれに違う動きをつけたいときに、とても便利です。
変身の決め手は、上下の線の top 値を真ん中(10px)に揃えてから回転させるところ。同じ位置に重ねたうえで、+45deg と -45deg に回すから、きれいな「×」になるんです。最初は紙にペンで書いてみると、動きがイメージしやすいですよ。
三本線が「×」にくるっと変わって、メニューがふわっと現れる。このちょっとした演出があるだけで、サイトの印象がぐっとプロっぽくなります。
ちょっと気をつけたい3つのこと
動くものができたら、もうひとがんばり。実務で「ちゃんとしたサイト」として通用させるために、知っておきたい3つのポイントをお伝えします。
1. スマホだけで表示する
ハンバーガーメニューは基本的にスマホ向けの仕組みです。PC画面では普通の横並びナビにして、画面が狭くなったときだけハンバーガーに切り替える。これを実現するのがメディアクエリです。
/* PCではハンバーガーボタンを隠す */
.menu-btn { display: none; }
/* スマホサイズになったら表示を切り替える */
@media (max-width: 768px) {
.menu-btn { display: block; }
.menu { max-height: 0; overflow: hidden; }
.menu-checkbox:checked ~ .menu { max-height: 300px; }
}
2. アクセシビリティを意識する
視覚的には隠したチェックボックスですが、スクリーンリーダー(画面の内容を音声で読み上げるソフト)にはちゃんと伝わるようにしたいですよね。display: none で完全に消すと読み上げもされなくなってしまうので、見た目だけ隠す書き方を使います。
.menu-checkbox {
position: absolute;
opacity: 0;
width: 1px;
height: 1px;
overflow: hidden;
}
合わせて、ラベルには aria-label="メニューを開く" を付けてあげると、より親切になります。アクセシビリティは「あとから足す」ではなく、最初から組み込むのが理想です。
3. ハンバーガーメニューは万能ではない
最後にひとつだけ。ハンバーガーメニューは便利ですが、「中身が見えない」という弱点があります。タップしないとどんなメニューがあるかわからないので、訪問者が深いページに進んでくれない、というデメリットも。重要なリンクが3〜4個しかないなら、横並びのまま小さくしたり、下部に固定するナビにしたほうが親切な場合もあります。
まとめ
- ハンバーガーメニューはJavaScriptなしでも、<input type="checkbox"> と :checked 擬似クラスを使えばCSSだけで作れる
- 仕組みのカギは、ラベルとチェックボックスを for と id で結びつけ、ラベル=ハンバーガーアイコンに見立てること
- 開閉アニメーションは max-height + transition の組み合わせが定番。height: auto ではアニメーションできない
- 三本線が「×」に変身する演出は、3本のspanを絶対配置で重ね、チェック時に rotate と opacity で動かして実現する
- 一般兄弟結合子 ~ は「チェックボックスの状態を、後ろにある要素に伝える」ための重要なセレクタ
- メディアクエリでスマホ時だけ表示し、視覚的に隠したチェックボックスもスクリーンリーダーには届くように配慮する
- 「作れる」だけでなく「使うべきかどうか」を判断できるようになることが、デザイナーとしての一歩先のステップ