【完全保存版】CSSだけで作るスマホメニュー実装|ハンバーガー+スライドで崩れない・横スクロールも潰す

【完全保存版】CSSだけで作るスマホメニュー実装|ハンバーガー+スライドで崩れない・横スクロールも潰す

2025.12.21

はじめに|スマホメニュー、作るのは簡単。でも“運用で壊れやすい”

スマホ対応のWebサイトを作るとき、ほぼ必ず必要になるのが「スマホ用メニュー」です。

  • スマホでナビゲーションをどう表示すればいい?
  • ハンバーガーメニューをCSSだけで作れる?
  • JavaScriptは使わないとダメ?

作れます。
ただ、動くだけだとあとで困りがちです。

  • 開くけど背景が押せる(誤タップ)
  • メニュー内がスクロールできない
  • スライドさせたら横スクロールが出る(スマホ崩れ)
  • PC表示に戻したらメニューが変な位置のまま

私も昔、right:-100% で隠したメニューが原因で、スマホだけ横スクロールが出て焦りました。
見た目は隠れてるのに「画面外に実体が残ってる」状態だったんですよね。

この記事では「スマホ メニュー css」で検索してきた人向けに、
CSSだけで実装しつつ、事故りやすいポイントを最初から潰す作り方をまとめます。


スマホメニューとは何か

スマホメニューは、スマートフォン表示時に使われるナビゲーションのことです。

よくある形はこの3つ。

  • ハンバーガーメニュー(≡)
  • スライドメニュー(右/左から出る)
  • フルスクリーンメニュー(画面を覆う)

この中で一番使われるのがハンバーガーメニュー。
見た目がスッキリするし、実装も軽めです。


なぜスマホ専用メニューが必要なのか

PC用ナビをそのままスマホに持ってくると、

  • 横幅に収まらない
  • 文字が小さくて押しづらい
  • 画面がごちゃごちゃする

が起きます。
だからスマホは「折りたたみ」が基本になります。


CSSだけでスマホメニューは作れる?

作れます。
ポイントはこれだけです。

  • checkboxで「開いてる/閉じてる」を持つ
  • labelでタップ操作を作る
  • :checked で表示を切り替える

ただ、実務で困りにくい形にするなら追加でこれも入れます。

  • 背景タップで閉じる(オーバーレイ)
  • メニュー内スクロール
  • 横スクロール問題が出にくい隠し方(transform)
  • DevToolsで原因が追いやすいセレクタ設計

まず動かす|スマホメニューの基本構造(HTML)

最小構成より、運用で困りにくい形を最初から置きます。

<input type="checkbox" id="menu-toggle" class="menu-toggle">

<label for="menu-toggle" class="menu-button" aria-label="メニューを開く">
  <span></span>
  <span></span>
  <span></span>
</label>

<label for="menu-toggle" class="menu-overlay" aria-hidden="true"></label>

<nav class="menu" aria-label="グローバルナビゲーション">
  <ul class="menu__list">
    <li><a href="#">ホーム</a></li>
    <li><a href="#">サービス</a></li>
    <li><a href="#">お問い合わせ</a></li>
  </ul>
</nav>

ポイント(ここを外すと動かない)

  • checkboxが開閉状態を持つ
  • menu-button(label)を押すとcheckedが切り替わる
  • overlayもlabelにして背景タップで閉じる
  • checkboxより後ろにmenuがある(~ セレクタで効かせる)

ハンバーガーボタンのCSS(三本線)

.menu-button {
  width: 32px;
  height: 26px;
  display: inline-flex;
  flex-direction: column;
  justify-content: space-between;
  cursor: pointer;
}

.menu-button span {
  display: block;
  height: 3px;
  background: #333;
  border-radius: 2px;
}

checkboxは「display:none」より安全に隠す

動きはしますが、後で扱いづらくなることがあるので、見えない場所に置きます。

.menu-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

メニューを初期状態で隠す(横スクロールが出にくい方法)

right:-100% で隠すと、スマホで横スクロールが出ることがあります。
なので、transformで画面外に飛ばす方式を使います。

.menu {
  position: fixed;
  top: 0;
  right: 0;
  width: min(80vw, 360px);
  height: 100svh;
  background: #fff;

  transform: translateX(100%);
  transition: transform 0.3s ease;

  z-index: 1001;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

クリックでメニューを表示する(checkedで切り替え)

.menu-toggle:checked ~ .menu {
  transform: translateX(0);
}

仕組み(かみ砕き)

  • checkboxがcheckedになる
  • checkedのときだけmenuのtransformを0にする
  • transitionでスライドして見える

背景タップで閉じる(オーバーレイを出す)

背景が触れると、ユーザーは迷います。
オーバーレイを入れて、タップで閉じられるようにします。

.menu-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);

  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;

  z-index: 1000;
}

.menu-toggle:checked ~ .menu-overlay {
  opacity: 1;
  pointer-events: auto;
}

overlayもlabelなので、タップするとcheckedが外れて閉じます。
JavaScriptなしで「背景タップ閉じ」が完成します。


左からスライドするスマホメニューにする

右→左は、transform方向を変えるだけです。

.menu {
  left: 0;
  right: auto;
  transform: translateX(-100%);
}

.menu-toggle:checked ~ .menu {
  transform: translateX(0);
}

レスポンシブ対応(PCでは通常ナビに戻す)

スマホ専用にしたいなら、ここを入れます。

@media (min-width: 769px) {
  .menu-button,
  .menu-overlay {
    display: none;
  }

  .menu {
    position: static;
    transform: none;
    height: auto;
    width: auto;
    overflow: visible;
    transition: none;
    z-index: auto;
  }
}

スマホメニューでよくあるトラブルと解決

メニューが閉じない/開かない

原因はだいたいこれです。

  • for="menu-toggle"id="menu-toggle" が合ってない
  • セレクタが合ってない(+~ を混同)
  • HTMLの並び順が違う(checkboxより前にmenuがある)

DevToolsでの確認手順

  1. F12 → Elements
  2. #menu-toggle を選択
  3. checked が付くか見る(クリックでも付く)
  4. .menu を選択
  5. Stylesで transform が当たっているか確認(打ち消し線が出ていないか)

checkedは付くのに動かないなら、ほぼセレクタか並び順です。


メニュー内がスクロールできない

.menu {
  overflow-y: auto;
  height: 100svh;
}

これで解決することが多いです。


背景がクリックできてしまう

  • overlayを入れる
  • z-indexをmenuより一段下にする

この記事の構成なら、背景は基本触れません。


横スクロールが出る(スマホ崩れ)

原因はこの辺が多いです。

  • 100vw の使いすぎ
  • right:-100% 系の隠し方で画面外に実体が残る
  • 長い英数字が折り返されない

長い文字の対策はこれ。

.menu a {
  overflow-wrap: anywhere;
}

CSSだけのスマホメニューのメリット・デメリット

メリット

  • JavaScript不要で軽い
  • 実装がシンプル
  • 小規模サイト・LPなら十分運用できる

デメリット

  • フォーカス制御など細かいアクセシビリティ対応は限界がある
  • aria-expandedの切り替えなど「状態に合わせた属性更新」はCSSだけでは難しい

まずはCSSで組んで、必要になったらJavaScriptを足す。
この順番が一番ラクです。


まずはこれでOK|コピペ用まとめコード

HTML

<input type="checkbox" id="menu-toggle" class="menu-toggle">

<label for="menu-toggle" class="menu-button" aria-label="メニューを開く">
  <span></span><span></span><span></span>
</label>

<label for="menu-toggle" class="menu-overlay" aria-hidden="true"></label>

<nav class="menu" aria-label="グローバルナビゲーション">
  <ul class="menu__list">
    <li><a href="#">ホーム</a></li>
    <li><a href="#">サービス</a></li>
    <li><a href="#">お問い合わせ</a></li>
  </ul>
</nav>

CSS(右からスライド)

.menu-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.menu-button {
  width: 32px;
  height: 26px;
  display: inline-flex;
  flex-direction: column;
  justify-content: space-between;
  cursor: pointer;
}

.menu-button span {
  display: block;
  height: 3px;
  background: #333;
  border-radius: 2px;
}

.menu-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
  z-index: 1000;
}

.menu {
  position: fixed;
  top: 0;
  right: 0;
  width: min(80vw, 360px);
  height: 100svh;
  background: #fff;
  transform: translateX(100%);
  transition: transform 0.3s ease;
  z-index: 1001;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.menu-toggle:checked ~ .menu-overlay {
  opacity: 1;
  pointer-events: auto;
}

.menu-toggle:checked ~ .menu {
  transform: translateX(0);
}

.menu a {
  overflow-wrap: anywhere;
}

@media (min-width: 769px) {
  .menu-button,
  .menu-overlay {
    display: none;
  }

  .menu {
    position: static;
    transform: none;
    height: auto;
    width: auto;
    overflow: visible;
    transition: none;
    z-index: auto;
  }
}

まとめ|スマホメニューは「仕組み+事故対策」で完成度が上がる

CSSだけでもスマホ用メニューは作れます。
ただ、実務で困らない形にするなら、ここがポイントです。

  • checkbox+labelで開閉
  • transformで隠して横スクロール問題を回避しやすくする
  • overlayで背景タップ閉じ&誤タップ防止
  • overflowでメニュー内スクロール
  • DevToolsでcheckedと打ち消し線を見て原因を切り分ける

「スマホ メニュー css」で探しているなら、
まずはこの記事の基本形をコピペして動かしてみてください。
動いたら、配色や幅、ボタンの位置をサイトに合わせて整えるだけです。

タグ:

#CSS #HTML #スマホ メニュー css #ハンバーガーメニュー #スライドメニュー #レスポンシブ #横スクロール #スマホ崩れ