「CSSだけで作るハンバーガーメニュー」JavaScript不要、チェックボックスで動く仕組みから丁寧に

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

そもそもハンバーガーメニューって?

三本線のアイコンをタップすると、メニューがふわっと開く。スマホサイトでよく見る、あの仕組みです。アイコンの形がハンバーガー(パン・パティ・パン)に似ているから、ハンバーガーメニューと呼ばれるようになりました。かわいい名前ですよね。

このメニュー、多くの人が「JavaScriptで開いたり閉じたりするもの」と思っています。実際、現場でもJavaScriptで実装されることが多いです。でも実は、<input type="checkbox"> をうまく使うと、CSSだけでも同じ動きが作れるんです。

「JavaScriptをまだ勉強していないから、ハンバーガーメニューはまだ無理…」と思っていた方、大丈夫です。今日はCSSだけで動く方法を、ひとつずつ丁寧に見ていきましょう。仕組みがわかれば、応用もきくようになりますよ。

📌 この記事のゴール
CSSだけで動くハンバーガーメニューを、自分の手で完成させること。仕組みが理解できれば、色や動きを変えるカスタマイズも自由自在です。

仕組みのキモは「チェックボックス」

CSSだけでメニューを開閉するために使うのが、<input type="checkbox"> です。チェックボックスには「チェックされている/されていない」という2つの状態がありますよね。この状態の切り替わりを、CSSの :checked 擬似クラスで拾って、メニューを表示/非表示する。これがすべての仕組みです。

「でもチェックボックスって、あの四角い箱のことでしょ? ハンバーガーアイコンと関係なくない?」と思いますよね。ここが今回いちばんおもしろいポイントです。チェックボックス本体は display: none で見えなくしておいて、代わりに <label> でハンバーガーアイコンを作るんです。label をクリックすると、紐づいたチェックボックスのオン/オフが切り替わる——HTMLの基本機能ですね。これを利用します。

身近な例で言うと、スイッチと電球の関係に似ています。チェックボックスは壁の中に隠れた配線(スイッチの本体)。ラベルは表に出ている押しやすいスイッチカバー。そしてメニューが電球です。私たちが操作するのはカバーだけ。中の配線がオン/オフを切り替え、それに反応して電球が光る。CSSのハンバーガーメニューも、これと同じ構造で動いています。

HTML — 最小構成
<!-- チェックボックス本体(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 と一致していることで、ラベルとチェックボックスが「結びつき」ます。この結びつきがあるから、ラベルをクリックするだけでチェック状態が切り替わるんですね。

シンプル版を作ってみよう

まずは、いちばんシンプルな「クリックで開いて、もう一度クリックで閉じる」だけのメニューを作ります。アイコンの変化はあとで足すとして、ここでは開閉の動きだけに集中しましょう。

CSS — シンプル開閉版
/* チェックボックスは隠す */
.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 を変える」という意味になります。難しそうな名前ですが、要は「お兄ちゃんの状態に応じて、弟の見た目を変える」というイメージで覚えてしまいましょう。

▶ Live Demo — ≡ をクリックしてみてください

動きましたか? 動いた方、おめでとうございます! JavaScriptを1行も書いていないのに、ちゃんとメニューが開いて閉じる。これがCSSの底力です。

⚠️ よくあるつまずき
「クリックしても何も起きない…」というとき、ほとんどの場合は labelfor 属性と、チェックボックスの id が一致していないことが原因です。スペルミス、半角/全角、ハイフンとアンダースコアの違いなど、ここはじっくり見直してみてくださいね。私も最初の頃、ここで何度も詰まりました。

三本線アイコンを「×」に変身させよう

シンプル版が動いたら、次はちゃんとハンバーガーらしい「三本線アイコン」を作って、メニューを開いたときに「×」に変身させてみましょう。ここがいちばんの見せ場です。

仕組みはシンプルです。3本の <span> を縦に並べて三本線を作り、チェックされたら——上の線は45度回転して中央へ、真ん中の線は消え、下の線はマイナス45度回転して中央へ。これで「×」が完成します。

CSS — アイコン変身版(要点だけ)
/* 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 に回すから、きれいな「×」になるんです。最初は紙にペンで書いてみると、動きがイメージしやすいですよ。

▶ Live Demo — アイコンが「×」に変わるバージョン

三本線が「×」にくるっと変わって、メニューがふわっと現れる。このちょっとした演出があるだけで、サイトの印象がぐっとプロっぽくなります。

💡 KANONのワンポイント
transition の時間は 0.3s 前後がおすすめです。短すぎると「カクッ」と切り替わって硬い印象に、長すぎると「もたつく」印象になります。0.25s0.4s の間で、自分のサイトの雰囲気に合うリズムを探してみてくださいね。

ちょっと気をつけたい3つのこと

動くものができたら、もうひとがんばり。実務で「ちゃんとしたサイト」として通用させるために、知っておきたい3つのポイントをお伝えします。

1. スマホだけで表示する

ハンバーガーメニューは基本的にスマホ向けの仕組みです。PC画面では普通の横並びナビにして、画面が狭くなったときだけハンバーガーに切り替える。これを実現するのがメディアクエリです。

CSS — 768px以下でハンバーガーを表示
/* 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 で完全に消すと読み上げもされなくなってしまうので、見た目だけ隠す書き方を使います。

CSS — アクセシブルに隠す方法
.menu-checkbox {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

合わせて、ラベルには aria-label="メニューを開く" を付けてあげると、より親切になります。アクセシビリティは「あとから足す」ではなく、最初から組み込むのが理想です。

3. ハンバーガーメニューは万能ではない

最後にひとつだけ。ハンバーガーメニューは便利ですが、「中身が見えない」という弱点があります。タップしないとどんなメニューがあるかわからないので、訪問者が深いページに進んでくれない、というデメリットも。重要なリンクが3〜4個しかないなら、横並びのまま小さくしたり、下部に固定するナビにしたほうが親切な場合もあります。

📌 覚えておこう
デザインのテクニックは「使えるかどうか」だけでなく「使うべきかどうか」を考えるとさらに上達します。CSSだけでハンバーガーが作れるようになった今こそ、「このサイトに本当に必要かな?」と一度立ち止まって考えてみてください。

まとめ

  • ハンバーガーメニューはJavaScriptなしでも、<input type="checkbox">:checked 擬似クラスを使えばCSSだけで作れる
  • 仕組みのカギは、ラベルとチェックボックスを forid で結びつけ、ラベル=ハンバーガーアイコンに見立てること
  • 開閉アニメーションは max-height + transition の組み合わせが定番。height: auto ではアニメーションできない
  • 三本線が「×」に変身する演出は、3本のspanを絶対配置で重ね、チェック時に rotateopacity で動かして実現する
  • 一般兄弟結合子 ~ は「チェックボックスの状態を、後ろにある要素に伝える」ための重要なセレクタ
  • メディアクエリでスマホ時だけ表示し、視覚的に隠したチェックボックスもスクリーンリーダーには届くように配慮する
  • 「作れる」だけでなく「使うべきかどうか」を判断できるようになることが、デザイナーとしての一歩先のステップ