本文へスキップ

ハンバーガーメニュー

三本線アイコンが × に変形しながらメニューが横からスライドイン。iframe内対応のposition:absolute実装。

プレビュー

クリック

操作クリック/タップで動きます。

使いどころ

ナビ項目が4〜6個程度あり、モバイル幅ではヘッダーに収まりきらない画面に向く。ロゴとハンバーガーボタン1つだけを常時表示し、必要なときだけドロワーを開くことで、狭い横幅を圧迫しない。逆に、PC幅で常時ナビを横並び表示できる余白があるなら、開閉の一手間を挟むこのパターンは不要で、通常のヘッダーナビの方がクリック数が少なく済む。また、画面遷移のたびに何度もメニューへ戻る用途(ECのカテゴリ切替など)では開閉の摩擦がストレスになりやすいので、タブバーやボトムナビのように常時見えるナビゲーションの方が向くことが多い。三本線が×へ変形しつつ右からドロワーがスライドインし、背後に暗いオーバーレイが重なるという、モバイルUIで最も定番の組み合わせになっている。

仕組み

三本線から×への変形は、1本目をtranslateY(7px) rotate(45deg)、2本目をopacity:0とscaleX(0)で消し、3本目をtranslateY(-7px) rotate(-45deg)にすることで上下のバーが中央で交差して×に見える仕組み。transform-originをcenterにしているため回転軸がぶれない。ドロワー本体はtransform: translateX(100%)からtranslateX(0)への移動だけで出し入れし、z-index 20でオーバーレイ(z-index 10)より前面に重ねる。open()/close()の2関数がis-openクラスとaria-expanded/aria-hidden属性をまとめて同期させる設計。見落とせない点として、.hb-root自体がposition:relative; overflow:hidden; width:360px; height:240pxのカード枠になっており、.hb-drawerはposition:absoluteでこのルート基準に配置されている。これはiframeプレビュー内で完結させるための実装で、実ページに組み込むときは.hb-drawerと.hb-overlayをposition:fixedに変え、hb-rootのoverflow:hiddenを外さないと、ドロワーが親要素の高さで切り取られてしまう。

実装の注意

最大の注意点は、このデモのposition:absolute実装をそのまま本番のヘッダーへ移植すると、ドロワーが親要素の高さ(240px)で切れてしまうこと。実際の全画面ドロワーにするには.hb-drawerと.hb-overlayをposition:fixedに変え、hb-root側のoverflow:hiddenの制約を外す作業が要る。ドロワー内のリンクはhref="#"のままだとクリックでページ先頭へ遷移してしまうため、デモではe.preventDefault()で止めてからclose()を呼んでいるが、実装時はこのpreventDefaultを外し、実際のURLへ書き換えるのを忘れないこと。もう一つ、開いている間に背景(.hb-main)がスクロールできてしまう点も手当てされていない。長いコンテンツの裏でドロワーを開くと、指でスクロールしたつもりが背景ごと動く体験になるため、開いている間はbodyにoverflow:hiddenを当てるなどの背景スクロールロックを別途足す必要がある。

アクセシビリティ

aria-expandedはhb-btnで、aria-hiddenはhb-drawerで、それぞれopen()/close()に合わせて同期している。ただしフォーカス管理は実装されておらず、開いたときにドロワー内の最初のリンクへフォーカスが移動しない、閉じたときにトリガーのhb-btnへフォーカスが戻らない、という2点が抜けている。またEscキーで閉じる処理もない。もう一つの弱点は、閉じている間ドロワーはaria-hidden="true"になるが、中のリンクにtabindex="-1"を明示していないため、Tabキーでの移動順序によっては見えないはずのリンクにフォーカスが入ってしまう可能性がある(aria-hiddenだけでは視覚的な非表示を伴わずフォーカス制御としては不完全)。ブラウザがinert属性に対応しているなら、is-openがfalseの間.hb-drawerにinertを付けるのが、これらをまとめて解決する最も確実な方法になる。開いている間のフォーカストラップも本番実装では追加すべき。

調整して使う

触る値はドロワーの出現方向(右から/左から)、幅(現在60%、固定280pxなどに変える手もある)、オーバーレイの濃さと有無、開閉のtransition時間(現在0.3s)。三本線の変形を×ではなく矢印やチェックに変える表現もあるが、その場合は各barのtransform値をアイコンの形に合わせて作り直す必要がある。ドロワーをoverflow:hiddenの親から解放してposition:fixedにすれば、幅を100%にした全画面メニュー(オーバーレイ不要)にも展開できる。ロゴとボタンだけのヘッダーではなく、検索アイコンなど他のアクションを右側に並べる構成にする場合は、hb-header内のjustify-content: space-betweenを崩さないよう配置し直すことになる。

コード(コピーして使えます)

<div class="hb-root">
  <header class="hb-header">
    <span class="hb-logo">MyApp</span>
    <button class="hb-btn" aria-label="メニューを開く" aria-expanded="false">
      <span class="hb-bar"></span>
      <span class="hb-bar"></span>
      <span class="hb-bar"></span>
    </button>
  </header>
  <nav class="hb-drawer" aria-hidden="true">
    <ul>
      <li><a href="#">ホーム</a></li>
      <li><a href="#">サービス</a></li>
      <li><a href="#">実績</a></li>
      <li><a href="#">お問い合わせ</a></li>
    </ul>
  </nav>
  <div class="hb-overlay"></div>
  <main class="hb-main">
    <p class="hb-hint">右上の ☰ をクリック</p>
  </main>
</div>

タグ

同じカテゴリ「ナビ・リスト操作」のほかのパーツ

関連パーツ