【jQuery】ハンバーガーメニューの作り方【ボタンアニメーションと上からスライドイン|CodePen付き】

jQueryハンバーガーメニューの簡単な作り方
SIM

こんにちは、SIMです。今日はjQueryで作る最も一般的なハンバーガーメニューの作り方を紹介します。

なお、この記事はコードの構造を分かりやすくするために、メニューボタンとメニュー本体部分に分けて説明しています。実際のjQureryは一つにまとまっているので、そういうイメージで読み進めて下さい。

今回、ご紹介するハンバーガーメニューの機能をまとめたのが、下のリストです。

ご紹介するハンバーガーメニューの機能リスト
  • ハンバーガー型ボタンを押すとドロワーメニューが上からスライドインで現れる
  • ハンバーガー型ボタンはクリックするとX印になる
  • ドロワーメニューが展開中は背景が暗くなる
  • ドロワーメニューが展開中は背景のスクロールが禁止される
  • ハンバーガー型ボタン(X印)をクリックするとドロワーメニューがスライドアップして上に消える
  • 暗い背景をクリックしても、ドロワーメニューはスライドアップで消える
  • キーボードのESCキーを押してもドロワーメニューはスライドアップで消える
SIM

まずは完成品のハンバーガーメニューの動きとコードをご確認下さい。

(スマホなどの小さい画面の場合はResultボタンをタップすると実際の表示が見れますよ)。

See the Pen ハンバーガーメニュー by s sim (@s-sim) on CodePen.

目次

メニューボタンのアニメーション

SIM

はじめにハンバーガーメニューのボタン(三本線の部分)の作り方を紹介します。

HTMLの構造

SIM

HTMLは、ハンバーガーのマークだけなら3行、「MENU」の文字を入れても4行という短いコードで作れちゃいます。

<!-- ハンバーガーメニューのボタン -->
<div class="l-sp-header_ham-menu">
 <div class="menu-txt">MENU</div>
 <div class="openbtn1"><span></span><span></span><span></span></div>
</div>

このうちjQueryと連動しているのは、spanタグが連続で並んでいる「class=”openbtn1″」のdivダグだけです。

CSSの構造 | 三本線がX印になるアニメーション

SIM

三本線とそのアニメーションに関係するCSSは長いです。
ただし、この記事で長いコードはココだけで、後は全部短いです。

/* ---------------------------- */
/* ハンバーガーメニューのボタン */
/* ---------------------------- */
.l-sp-header_ham-menu {
  width: 60px;
  height: 60px;
  border-radius: 3px;
  background-color: #023047;
  color: #fff;
  font-size: 13px;
  font-weight: 400;
  text-align: center;
  padding-top: 6px;
}
/* ---------------------------- */
.open-btn1 {
  position: relative; /*ボタン内側の基点となるためrelativeを指定*/
  cursor: pointer;
  width: 60px;
  height: 40px;
  margin-top: 2px;
}
/*ボタン内側:三本線のスタイル*/
.open-btn1 span {
  display: inline-block;
  transition: all 0.4s; /*アニメーションの設定*/
  position: absolute;
  left: 12px;
  height: 2px; /*Android端末で線の太さの違い出る対策*/
  transform: scaleY(0.5) translateY(1px); /*Android端末で線の太さの違い出る対策*/
  border-radius: 2px;
  background: #fff;
  width: 62%;
}
/* 上の線 */
.open-btn1 span:nth-of-type(1) {
  top: 4px;
}
/* 真ん中の線 */
.open-btn1 span:nth-of-type(2) {
  top: 14px;
}
/* 下の線 */
.open-btn1 span:nth-of-type(3) {
  top: 24px;
}
/* ---------------------------- */
/*activeクラスが付与されると線が回転して×に*/
.open-btn1.active span:nth-of-type(1) {
  top: 8px;
  left: 16px;
  transform: translateY(6px) rotate(-45deg);
  width: 50%;
  height: 1px; /*Android端末で線の太さの違い出る対策*/
}
.open-btn1.active span:nth-of-type(2) {
  opacity: 0; /*真ん中の線は透過*/
}
.open-btn1.active span:nth-of-type(3) {
  top: 20px;
  left: 16px;
  transform: translateY(-6px) rotate(45deg);
  width: 50%;
  height: 1px; /*Android端末で線の太さの違い出る対策*/
}
ハンバーガーメニューのボタンについての解説
  • ボタンのカスタマイズ:spanタグの数字を変えることで、サイズや線の感覚をカスタマイズできます。
  • ボタンアニメーションについて:spanタグにactiveクラスが付与されると、上の線が-45度回転、真ん中の線が消えて、下の線が45度回転する仕組みになっています。
  • activeクラス付与と剥奪:ハンバーガーメニューのボタンクリックでアクティブクラスが付いたり、取れたりする仕組みになっています(制御はjQuery)。

上のCSSに関する補足説明|2024.7.17追記

上のCSSでは、下記の表示バグに関する対策も施しています。

その表示バグというのは、Android端末などで、ハンバーガーメニューの3本線の太さがそれぞれ違って見えるというものです。

例えば、私の経験したケースでは、EdgeとFirefoxでは真ん中の線がほかより太く、Chromeでは下の線が細く見えるとうバグです。

このバグの対策として、上のコードに下記の記述が加えられています。

なお、ここでは線の太さは1pxとしています。

29行目と30行目

  height: 2px; /*Android端末で線の太さの違い出る対策*/
  transform: scaleY(0.5) translateY(1px); /*Android端末で線の太さの違い出る対策*/

heightを2倍の2pxに設定し、transformで50%の1pxに戻すという方法です。

54行目と64行目

 height: 1px; /*Android端末で線の太さの違い出る対策*/

これはバツ印となる2本線ですが上で太さ2pxとしたため、このままではバツ印のみ線が太くなってしまいます。

そこで、新たにバツ印のCSSにも高さ1pxを記述することで、線の太さが変わらないようにしました。

詳しくはこちらを参照願います。

この表示バグの原因はディスプレイの表示倍率(Device Pixel Ratio)でして、詳しくは下記のteratailのQ&Aを参照願います。

teratail「CSS ハンバーガーメニューの3本線の内1つの線だけ太さが異なって表示されてしまう。」

https://teratail.com/questions/4ax8gozl274ll5

jQuery | 三本線がX印になるアニメーション

SIM

基本的な仕組みは、三本線のメニューボタンがクリックされたらactiveクラスの脱着が起きるようになっています。

ハンバーガー型ボタンのjQueryによる動作の概要

三本線のボタン(open-btn1)がクリックされると:$(‘.open-btn1’).click(function() {…

  • open-btn1クラスにactiveクラスの脱着が起こり、三本線がX印になったり、X印から三本線に戻ったりする
    $(this).toggleClass(‘active’);

ドロワーメニュー以外の背景部分をクリックした時は:$(‘.sp-nav-close’).click(function() {…

  • ボタン(X印)からactiveクラスを剥奪し、三本線に戻る
    $(‘.open-btn1’).removeClass(‘active’);

キーボードのESCキーを押した時は:$(window).keyup(function(e){if(e.keyCode == 27){…

  • ボタン(X印)からactiveクラスを剥奪し、三本線に戻る
    $(‘.open-btn1’).removeClass(‘active’);
SIM

jQueryのすべてのコードは下の方に載せておきます。

メニュー本体がスライドインするアニメーション

SIM

続いて、ハンバーガーメニューのボタンをクリックしたらドロワーメニューが上からスライドインしてくるコードを紹介します。

HTMLの構造

SIM

HTML構造はシンプルで、上で解説した三本線ボタンを含むヘッダーバーの下に、①暗い背景と、②ドロワーメニュー本体を同じ階層に書くだけです。

ハンバーガーメニューのHTML構造の概要

下記の要素はすべて同じ階層に置きます。

  • ヘッダーバー:この中に三本線(ハンバーガー型)ボタンを置く(class=”open-btn1″)
  • ドロワーメニュー用の暗い背景:class=”p-sp-nav-bg sp-nav-close”
  • ドロワーメニュー本体:class=”p-sp-nav” id=”sp-g-nav”

上の各要素の中身のHTML構造は自由に作ってもjQueryの動作に影響はありません。

<body>
  <header class="l-header">
    <!-- スマートフォン専用ヘッダー -->
    <div class="l-sp-header">
      <!-- ページタイトル -->
      <div class="l-sp-header_headline">
        <h1 class="l-sp-header_h1">SIMS-CODE</h1>
      </div>
      <!-- ハンバーガーメニューのボタン -->
      <div class="l-sp-header_ham-menu">
        <div class="menu-txt">MENU</div>
        <div class="open-btn1"><span></span><span></span><span></span></div>
      </div>

    </div>
    <!-- ナビの背景 -->
    <div class="p-sp-nav-bg sp-nav-close"></div>
    <!-- スマホ用グローバルナビ -->
    <nav class="p-sp-nav" id="sp-g-nav">
      <ul class="p-sp-nav_ul">
        <li class="p-sp-nav_li">
          <a href="#" class="p-sp-nav_a">HOME</a>
        </li>
        <li class="p-sp-nav_li">
          <a href="#" class="p-sp-nav_a">唐揚げ定食 500円</a>
        </li>
        <li class="p-sp-nav_li">
          <a href="#" class="p-sp-nav_a">焼き肉定食 2,000円</a>
        </li>
        <li class="p-sp-nav_li">
          <a href="#" class="p-sp-nav_a">カツカレー 1,200円</a>
        </li>
        <li class="p-sp-nav_li">
          <a href="#" class="p-sp-nav_a">ロースカツ定食 1,200円</a>
        </li>
        <li class="p-sp-nav_li">
          <a href="#" class="p-sp-nav_a">ハンバーグ定食 1,000円</a>
        </li>
        <li class="p-sp-nav_li">
          <a href="#" class="p-sp-nav_a">メンチカツ定食 1,000円</a>
        </li>
      </ul>
    </nav>
  </header>

  <main></main>
  <footer></footer>

  <!-- jqueryのスクリプト -->
  <script src="https://code.jquery.com/jquery-3.6.1.min.js"
    integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
</body>
HTMLでjQueryと連動する箇所について
  • body:ドロワーメニュー展開時にbodyにfixedクラスを付与して背景スクロールを禁止する
  • div class=”openbtn1″:activeクラスが脱着されることで三本線ボタン←→X印に変化
  • div class=”p-sp-nav-bg sp-nav-close”:ドロワーメニューの背景部分
  • nav class=”p-sp-nav” id=”sp-g-nav”ドロワーメニュー本体

CSSの構造 | メニュー本体上からスライドインするアニメーション

SIM

メニュー本体のCSSは次のとおりで、z-indexの説明は上のHTMLでしたとおりです。

body.fixed {
  position: fixed;
  width: 100%;
  height: 100%;
}

/* ---------------------------- */
/* スマートフォン用ヘッダー */
/* ---------------------------- */
.l-sp-header {
  width: 100%;
  z-index: 10;
  height: 80px;
  position: fixed;
  top: 0;
  left: 0;
  display: flex;
  justify-content: space-between;
  color: #023047;
  padding: 9px 20px;
  background-color: #8ecae6;
}

/* ---------------------------- */
/* メニュー本体 */
/* ---------------------------- */
/* 暗い背景 */
.p-sp-nav-bg{
  display: none;
  position: fixed;
  width: 100%;
  height: 100%;
  background-color: rgba(2,48,71, 0.6);
  top: 0;
  left: 0;
  /* z-index: 5; */
  transition: all 0.3s;
}
/* .bg-activeが付与された時 */
.p-sp-nav-bg.bg-active{
  display: block;
  transition: all 0.3s;
}

/* ナビゲーション全体を囲うタグ */
#sp-g-nav {
  position: fixed;
  z-index: 7;
  color: #fff;
  background-color: #023047;
  font-size: 16px;
  font-weight: 300;
  line-height: 1.3;
  width: 100%;
  top: -120%;
  transition: all 0.3s;
}
/*アクティブクラスがついたら表示位置変更*/
#sp-g-nav.panel-active {
  width: 100%;
  top: 80px;
  transition: all 0.3s;
}
/* ナビゲーション本体 */
.p-sp-nav_ul{
  width: 100%;
}
.p-sp-nav_li {
  height: 38px;
  border-bottom: 1px solid #fff;
}
.p-sp-nav_li:last-of-type {
  border-bottom: 0;
}
.p-sp-nav_a{
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  padding-left: 2em;
}

/* ---------------------------- */
/* メインエリアのスタイル */
/* ---------------------------- */
main{
  padding-top: 80px;
  text-align: center;
  color: #219ebc;
  font-size: 20px;
  font-weight: 600;
  line-height: 2;
}
.main-p{
  margin-top: 50px;
}
SIM

ドロワーメニューCSSの基本的な仕組みは、通常は非表示しておいてjQueryで特定のクラスが付与されたら表示位置に移動するようになっています。

その辺りを要約すると次のようになります。

ドロワーメニューがスライドインするCSSの概要

ドロワーメニュー本体

  • 通常top: -120%」で端末画面のはるか上に配置して画面上では見えないようにしておく。
  • 特定のクラスが付与された時:panel-activeクラスがメニュー本体(id=”sp-g-nav”)に付与されると、ちょうど見える位置(この場合はtop: 80px)までメニューが下がってくる仕組みになっている。

ドロワーメニューの背景

  • 通常diplay:noneで非表示
  • 特定のクラスが付与された時:bg-activeクラスが付与されるとdisplay: blockとなって表示される

body

  • 通常:スクロールできる
  • 特定のクラスが付与された時:fixedクラスが付与されるとposition: fixed;になりスクロールが禁止される

jQuery | メニュー本体が上からスライドインするアニメーション

SIM

本来、ドロワーメニューのjQueryはシンプルですが、今回は様々なオプション機能を盛り込んだため少し複雑になっています。

jQueryのコードの全容は以下のとおりです。

各コードの意味はコメントアウトとしてコード横に書きました。

$(function() {
	var scrollPos;//topからのスクロール位置
	$('.open-btn1').click(function() { //ボタンをクリックしたら

    $(this).toggleClass('active');//ボタン自身に activeクラスを付与し
    $('.p-sp-nav-bg').toggleClass('bg-active');//背景にbg-activeクラスを付与
    $('#sp-g-nav').toggleClass('panel-active');//ナビにpanel-activeクラスを付与

    if($(this).hasClass('active')){//もしボタンにactiveクラスが付いていれば
      scrollPos = $(window).scrollTop();//topからのスクロール位置を取得
      $('body').addClass('fixed').css({ top: -scrollPos });//背景固定

    }else{//もしボタンにactiveクラスが無ければ
      $('body').removeClass('fixed').css({ top: 0 });//背景固定を解除
      $(window).scrollTop(scrollPos);//元の位置までスクロール
    }
  });

  $('.sp-nav-close').click(function() { //背景をクリックしたら
    $('.open-btn1').removeClass('active');//ボタンからactiveクラスを剥奪
    $('#sp-g-nav').removeClass('panel-active');//ナビからpanel-activeクラスを剥奪
    $('.p-sp-nav-bg').removeClass('bg-active');//背景からbg-activeクラスを剥奪
    $('body').removeClass('fixed').css({ top: 0 });//背景固定を解除
    $(window).scrollTop(scrollPos);//元の位置までスクロール
	});    

	$(window).keyup(function(e){//キーをクリックして
		if(e.keyCode == 27){//ESCキーだったら
			$('.open-btn1').removeClass('active');//ボタンからactiveクラスを剥奪
			$('#sp-g-nav').removeClass('panel-active');//ナビからpanel-activeクラスを剥奪
			$('.p-sp-nav-bg').removeClass('bg-active');//背景からbg-activeクラスを剥奪
			$('body').removeClass('fixed').css({ top: 0 });//背景固定を解除
			$(window).scrollTop(scrollPos);//元の位置までスクロール
		}
	});
});
SIM

一応、jQueryについても簡単にコード解説をしておきます。
上のコードは大きく3つのパートに分かれていますので、一つずつ説明します。

ドロワーメニューメニューのjQueryの3つのパート
  1. ハンバーガー型(三本線)ボタンをクリックした時の動き
  2. ドロワーメニュー展開時に背景部分をクリックした時の動き
  3. キーボードのESCキーを押した時の動き

そして、大前提としてドロワーメニュー展開時に背景スクロールを禁止するために、Topからのスクロール量を取得するための変数について変数宣言をjQueryの最初にします。

$(function() {
	var scrollPos;//変数宣言:topからのスクロール位置

ハンバーガー型(三本線)ボタンをクリックした時のjQuery

ハンバーガー型(三本線)ボタンをクリックした時のjQueryの概要

ハンバーガー型(三本線)ボタンをクリックしたら:$(‘.open-btn1’).click(function() {

  • ボタン自身に activeクラスを脱着し、形状変化(三本線 <=> X印
    $(this).toggleClass(‘active’);
  • ドロワーメニューの背景にbg-activeクラスを脱着し、表示変化(非表示 <=> 表示
    $(‘.p-sp-nav-bg’).toggleClass(‘bg-active’);
  • ドロワーメニューにpanel-activeクラスを脱着し、表示変化(非表示 <=> 表示
    $(‘#sp-g-nav’).toggleClass(‘panel-active’);

このとき、もしボタンにactiveクラスが付いていれば
if($(this).hasClass(‘active’)){

  • topからのスクロール位置を取得
    scrollPos = $(window).scrollTop(); 予めこの上の階層で変数宣言(var scrollPos;)の必要あり
  • bodyにfixedクラスを付与:背景のスクロールを禁止し、現在のスクロール位置で固定
    $(‘body’).addClass(‘fixed’).css({ top: -scrollPos });

ボタンにactiveクラスが無ければ
}else{

  • bodyからfixedクラスを剥奪:スクロールできるようにし、一旦スクロール量をtopから0に変更
    $(‘body’).removeClass(‘fixed’).css({ top: 0 });
  • 背景を元のスクロール位置に合わせる:元のスクロール量=scrollPos
    $(window).scrollTop(scrollPos);
SIM

ここで難しく感じる箇所は背景のスクロール禁止命令だと思います。

背景スクロールの禁止jQueryはモーダルウィンドウのページでも解説しましたが、ハンバーガーメニューの場合にはさらに複雑になってif文にしないと動作しません

ハンバーガー型ボタンがactiveクラスを持っていれば背景スクロールを禁止して、持っていなければ背景スクロールを解禁するようなif文で作ってあります。

ドロワーメニュー展開時に背景部分をクリックした時のjQueryの動き

SIM

ドロワーメニューの暗い背景部分をクリックした時にもドロワーメニューが閉じる命令をjQueryで書いています。

ドロワーメニュー展開時に背景部分をクリックした時のjQueryの概要

ドロワーメニューの背景をクリックしたらボタンをクリックしたら:$(‘.sp-nav-close’).click(function() {

  • ボタンからactiveクラスを剥奪し、形状変化(X印 <=> 三本線
    $(‘.open-btn1’).removeClass(‘active’);
  • ドロワーメニューからpanel-activeクラスを剥奪し、スライドアップして非表示にする
    $(‘#sp-g-nav’).removeClass(‘panel-active’);
  • ドロワーメニューの背景からbg-activeクラスを剥奪し、非表示にする
    $(‘.p-sp-nav-bg’).removeClass(‘bg-active’);
  • bodyからfixedクラスを剥奪:スクロールできるようにし、一旦スクロール量をtopから0に変更
    $(‘body’).removeClass(‘fixed’).css({ top: 0 });
  • 背景を元のスクロール位置に合わせる:元のスクロール量=scrollPos
    $(window).scrollTop(scrollPos);

キーボードのESCキーを押した時のjQuery

SIM

キーボードのESCキーを押したときにもドロワーメニューが閉じる命令をjQueryで書いています。

キーボードのESCキーを押した時のjQueryの概要

ESCキーをクリックしたら
$(window).keyup(function(e){
if(e.key === “Escape”){

  • ボタンからactiveクラスを剥奪し、形状変化(X印 <=> 三本線
    $(‘.open-btn1’).removeClass(‘active’);
  • ドロワーメニューからpanel-activeクラスを剥奪し、スライドアップして非表示にする
    $(‘#sp-g-nav’).removeClass(‘panel-active’);
  • ドロワーメニューの背景からbg-activeクラスを剥奪し、非表示にする
    $(‘.p-sp-nav-bg’).removeClass(‘bg-active’);
  • bodyからfixedクラスを剥奪:スクロールできるようにし、一旦スクロール量をtopから0に変更
    $(‘body’).removeClass(‘fixed’).css({ top: 0 });
  • 背景を元のスクロール位置に合わせる:元のスクロール量=scrollPos
    $(window).scrollTop(scrollPos);
SIM

最後にCodePenをもう一度貼っておくので、動きやコードを確認してみて下さいね。

See the Pen ハンバーガーメニュー by s sim (@s-sim) on CodePen.

まとめ

SIM

jQueryで作るハンバーガーメニューを紹介しました。
基本、コピペで真似できると思うので少しでもこの記事を読んでくれた皆様のお役に立てれば幸いです。

ハンバーガーメニュー(ドロワーメニュー)に幾つかのパターンがあって、今回紹介したのは上からスライドインする最もオーソドックスなタイプです。この他によく見かける横からスライドインしていくるタイプもドロワーメニューの初期の座標を変更するだけで実装が可能です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

■清水WEB制作代表
■コーディング:WordPress(オリジナルテーマ制作等)・HTML・Sass・FLOCSS・JavaScript(jQuery)等
■集客力:YouTube/Instagram/ブログでそれぞれ登録者数16000人/フォロワー13000人/月間最大アクセス50000PVの集客実績があります
■文章作成:博士号所有、会社員時代は科学雑誌に寄稿していたので文章作成も得意です
■写真技術:Amazon Kindle出版で、写真集・撮影編集解説書を5冊好評発売中です

目次