スマートフォン向けのハンバーガーメニューボタンの動作方法（jQuery利用）

# ハンバーガーボタンの作り方

お久しぶりです。コウヤです。

今まで、Python関連の記事を中心に書いておりましたが、この度、WebデザインやWebコーディングのスキルを強化して、Webコーダーをまずは目指していきたいという気持ちが固まりました。
現在は副業または業務で活かすことを念頭にスキル強化中です。

さて、今回のWeb作成の課題で、ハンバーガーメニューの作り方を学ぶ機会があったので、実装方法を紹介したいと思います。

皆さんもスマートフォンでWebサイトを見ているときに、以下の画像にあるハンバーガーボタンを見かけることが多いと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/e4f003ec-94a0-9dc6-75c1-a4d33ba8633a.png)

さて、このボタンを押下すると、以下のように背景が薄く白くなり、ページ内リンクが出るようになりますが、今回はこれを実装することを考えていきたいと思います。

ここまでの背景デザインまで作成はしませんが、簡単に作れるように背景だけは変えていきたいと考えています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/59c7e510-0fc3-c3f2-cd84-e215f7915bfd.png)


## 必要な知識
HTML、CSS、jQueryの基本的知識

## 書き方について
まずはフォルダ構成は以下の通りとしております。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/4549c120-8092-f322-f581-a038ef4e0490.png)

### jQueryをダウンロードする
まずはこのハンバーガボタンを実装するに当たって、前提としてjQueryを導入する必要があります。
今後いろいろな機能を実装するので、あらかじめダウンロードしておきましょう。
https://jquery.com/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/c27d2d71-d57c-3aab-d8b4-2d80ecde6048.png)

そして以下から右クリックしてダウンロードを行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/e0eaa7d7-b589-097d-5358-2b0541fe65d2.png)

今回以下のフォルダ構成にしていますので、ダウンロードしたら、以下のjsフォルダ内に置きます。
今回は**jquery-3.7.0.min.js**というファイル名ですが、バージョンが上がり次第、名前は変わります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/d792dfcd-d06b-37de-bd25-115061335a7c.png)

jQueryを参照させるために、htmlファイルのheadタグ内に以下のコードを埋め込みます。

```index.html
    <script src="js/jquery-3.7.0.min.js"></script>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/5955ac29-501a-b133-27f3-964d3dee60e3.png)

これでjQueryの準備は完了です。



## ハンバーガーボタンの作り方
次に、ハンバーガーボタンの作り方について説明します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/46c1ea9e-885e-62da-3941-0b299f379ba1.png)

その前に、ハンバーガーボタンは基本的にスマートフォンなどの小型デバイスでしか使用しないため、以下**Chrome上で作業するときには画像のように横幅をiPhone SEサイズ**にしてください。
（下記のように作成するのが目的です）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/fe8f9f18-2ed4-a57a-8a4a-a78916691d9c.png)



まずはbodyタグ内に以下の内容を記載します。ハンバーガーボタンで使用するbuttonのクラス名は**fv__hamburger**とします。
```html:index.html
    <header id="fv">
        <button class="fv__hamburger">
            <div>
                <span></span>
                <span></span>
                <span></span>
            </div>
        </button>

    </header>
```


CSSで以下のように設定します。
ここで背景はハンバーガーボタンを使用したことが分かりやすいように青にしておきます。
```css:style.css
#fv {
  background-color: #00f;
  height: 667px;
  position: relative;
}

.fv__hamburger {
  cursor: pointer;
  position: fixed;/*スクロールしても固定*/
  border: 0px;
  top: 20px;
  right: 20px;
  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);/*ボタンに影を付ける*/
  background: #c89932;
  height: 48px;
  width: 48px;
  border-radius: 50%;/*ボタンを円形にしている（ここを変更することで四角形も可能）*/
  z-index: 10;/*最前面にくるように数値を大きくしている*/
}

```

すると、以下のようにボタンができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/0b4119d1-6c42-5670-a9ca-f03bfdbd5b3f.png)

そこに3つの横線を入れていきます。上記CSSの下に以下の内容を追記します。
```css:style.css
#fv {
※上と同じ
}

.fv__hamburger {
※上と同じ
}


.fv__hamburger span {
  display: inline-block;
  transition: all 0.4s;
  position: absolute;
  left: 15px;
  height: 2px;
  border-radius: 2px;
  background: #eee;
  width: 18px;
}

```


すると以下のように1本のみになるので、これを3本線にしていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/3fb37005-8360-a265-cf2c-9c94e3c418b9.png)

次に3本線になるように設定していきます（この3本線の形がハンバーガーのため、その名がついています）


```html:index.html
    <header id="fv">
        <button class="fv__hamburger">
            <div>
                <span></span>
                <span></span>
                <span></span>
            </div>
        </button>

    </header>
```

上記spanにそれぞれ位置を指定します。
```css:style.css
#fv {
※上と同じ
}

.fv__hamburger {
※上と同じ
}


.fv__hamburger span {
※上と同じ

}

.fv__hamburger span:nth-child(1) {
  top: 18px;
}

.fv__hamburger span:nth-child(2) {
  top: 23px;
}

.fv__hamburger span:nth-child(3) {
  top: 28px;
}
```


すると以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/4b44df72-6c99-81dd-2eeb-781f2574eeeb.png)


## リンクを表示させる
次にハンバーガーボタンを押下したした際に、✕となるように設定をしていきます。それと同時にリンク一覧を表示させることを考えていきます。

### 背景を変えてリンクを表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/6df6648a-0ef7-a5bb-bb64-255a805d8b72.png)
↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/915e1067-9dbb-d639-31f9-b306934786a6.png)

```html:index.html
    <header id="fv">
        <button class="fv__hamburger">
            <div>
                <span></span>
                <span></span>
                <span></span>
            </div>
        </button>


        <!-- リンク表示 #sp_bg-->
        <div id="sp__bg">
          <ul class="nav__menu">
              <li class="nav__menu_item"><b>リンク一覧</b></li>
              <li class="nav__menu_item"><a href="#about">この農園について</a></li>
              <li class="nav__menu_item"><a href="#product">メニュー一覧</a></li>
              <li class="nav__menu_item"><a href="#info">お知らせ</a></li>
              <li class="nav__menu_item"><a href="#FAQ">FAQ</a></li>
              <li class="nav__menu_item"><a href="#access">アクセス</a></li>
              <li class="nav__menu_item"><a href="#inquiry">お問い合わせ</a></li>
          </ul>
        </div> 
    </header>
```

同時にCSSの方も設定していきます。

```css:style.css
#fv {
※上と同じ
}

.fv__hamburger {
※上と同じ
}

.fv__hamburger span {
※上と同じ
}

.fv__hamburger span:nth-child(1) {
※上と同じ
}

.fv__hamburger span:nth-child(2) {
※上と同じ
}

.fv__hamburger span:nth-child(3) {
※上と同じ
}

#sp__bg {
  position: fixed;
  left: 0;
  top: 0;
  height: 100%;
  width: 100%;
  background: rgba(255, 255, 255, 0.9);
  text-align: center;
  z-index: 1;
}

#sp__bg .nav__menu {
  padding-top: 61.6px;
  font-size: 16px;
  line-height: 23px;
  color: #475950;
} 

#sp__bg .nav__menu a {
  font-weight: 700;
}

#sp__bg .logo_sp {
  margin-bottom: 10.6px;
}

#sp__bg .nav__menu .logo3 {
  margin-bottom: 50px;
}

#sp__bg .nav__menu_item {
  margin-bottom: 16px;
}

#sp__bg .nav__menu_item:nth-child(1) {
  font-size: 26px;
  font-weight: 700;
  color:#c89932;
} 

```

すると以下のように表示がされます。背景は先程まで青だったのに、今は薄い青色になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/4704f932-f196-d301-60c3-a62818a5e0d5.png)
これは、CSSの#sp__bgにおいて、backgroundを
background: rgba(255, 255, 255, 0.9);
としているためです。

```.css
#sp__bg {
  position: fixed;
  left: 0;
  top: 0;
  height: 100%;
  width: 100%;
  background: rgba(255, 255, 255, 0.9);
  text-align: center;
  z-index: 1;
}
```

このままではこのページを表示した瞬間から背景が見えずにいきなりリンクが表示されている状態ですので、これを**jQuery**を使って操作していきます。

まず、jsフォルダ内にscript_jQ.jsというファイルを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/4246164f-fa94-9b98-5ccc-1877d4f6c8d4.png)

そして、以下のコード
```.html
    <script src="js/script_jQ.js"></script>
```
を\</head>の直前に置きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/b486ef04-6600-e3eb-a6ce-ed2736b3df18.png)

そして、以下のように記載する。
このように記載することでリンクを一旦消すことができる。
```script_jQ.js
$(function(){

    //リンクを消す
	$('#sp__bg').hide();

});

```

\#sp__bg（\<div id="sp__bg">で囲まれた箇所）を一旦**hide()メソッド**で隠しています。

### ボタンを押下した際に✕にする。

先程リンクをhide()メソッドで隠しましたが、ハンバーガーボタンを押下した際に以下のように✕にすることを考えてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/56f5d28e-c816-f43d-68db-ebd3239b2488.png)

そのためにはまず✕のデザインをするためにCSSに内容を追加していきます。

```css:style.css
#fv {
※上と同じ
}

.fv__hamburger {
※上と同じ
}

.fv__hamburger span {
※上と同じ
}

.fv__hamburger span:nth-child(1) {
※上と同じ
}

.fv__hamburger span:nth-child(2) {
※上と同じ
}

.fv__hamburger span:nth-child(3) {
※上と同じ
}

#sp__bg {
※上と同じ
}

#sp__bg .nav__menu {
※上と同じ
} 

#sp__bg .nav__menu a {
※上と同じ
}

#sp__bg .logo_sp {
※上と同じ
}

#sp__bg .nav__menu .logo3 {
※上と同じ
}

#sp__bg .nav__menu_item {
※上と同じ
}

#sp__bg .nav__menu_item:nth-child(1) {
※上と同じ
} 

.fv__hamburger.active span:nth-child(1) {
    top: 30px;
    left: 15px;
    transform: translateY(-6px) rotate(45deg);
    width: 18px;
}

.fv__hamburger.active span:nth-child(2) {
    opacity: 0;
}

.fv__hamburger.active span:nth-child(3) {
    top: 18px;
    left: 15px;
    transform: translateY(6px) rotate(-45deg);
    width: 18px;
}
```

ボタンが押下されたときには、**.fv__hamburger.active**という名前のセレクタにしています。
今追加したCSSでは✕のデザインになっています。（ただし、**表向きにはまだ✕の表示はされていません。**）
ボタンの真ん中の線（span:nth-child(2)）をopacity:0;で透明にして、上（span:nth-child(1)）と下（span:nth-child(3)）の線をtransformを使って6px分上または下に移動して45度斜めにしたり、topの位置なども調整しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/35210461-033d-15be-34e8-ef97b8f4ab69.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/00af1278-7a01-a350-e4ee-3048a215735a.png)

前述の通り、**表向きにはまだ✕の表示はされていません。**
理由として、以下のように、buttonクラスがfv__hamburger.activeとなっていないからです。

```.html
        <button class="fv__hamburger">
            <div>
                <span></span>
                <span></span>
                <span></span>
            </div>
        </button>
```

これを **class="fv__hamburger.active"** にするために、jQueryで操作をしていきます。
script_jQ.jsファイルに追記をします。

```script_jQ.js
$(function(){

    //リンクを消す
	$('#sp__bg').hide();

    //もし、.fv__hamburger（ハンバーガーボタンが）がクリックされたら...の内容を書く
	$('.fv__hamburger').click(function(){
        //この中にクリックした際の内容を記載する

	});
});

```

実際にクリックされたときの内容を記載する。
```script_jQ.js
$(function(){

    //リンクを消す
	$('#sp__bg').hide();

    //もし、.fv__hamburger（ハンバーガーボタンが）がクリックされたら...の内容を書く
	$('.fv__hamburger').click(function(){

        //もし、ハンバーガーボタンに.activeクラスが付与(hasClass)されていた場合
		if($('.fv__hamburger').hasClass('active')){

            //こちらはボタンが✕の状態の処理
			$('#sp__bg').fadeOut(300);
			$(this).removeClass('active');

		}else{

            //こちらはボタンが三本線の状態の処理
			$('#sp__bg').fadeIn(300);
			$(this).addClass('active');

		}

	});
});

```
ここでifの条件
```
$('.fv__hamburger').hasClass('active')
```
についてですが、 **.fv__hamburder** に **active** クラスがあるかどうかを判定しています。そのために **hasClass()** メソッドを用いています。
つまり以下の状態であるかどうかを判断しようとしています。以下の状態（つまりボタンが✕の状態）であればTrueとなり、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/a0b9acf5-8a6e-7936-dd4f-803489cfb05b.png)

以下の状態であればFalseとなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/c5e61df3-07c3-11bf-605a-d7324a449632.png)


まずは先にelseの部分（今回であればFalseの場合）について説明していきます。

```.js
    //こちらはボタンが三本線の状態の処理
    $('#sp__bg').fadeIn(300);
    $(this).addClass('active');

```
から確認してみます。
ボタンが三本線だった際に、以下の#sp__bgの内容を表示させる必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/e8a3a54a-2d59-af49-22af-9bc654d50ce2.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/617db792-4a05-ed66-2332-cbebbd95aed3.png)

そのために、
**$('#sp__bg').fadeIn(300);**
でフェードインさせます。この例では300msかけてフェードインさせていますが、時間の調整は可能です。

さらに、
**$(this).addClass('active');**
でactiveクラスをadd（追加）しています。その証拠にChromeのコンソールを見ると以下のようにactiveが表示されているのが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/adfb7cb8-2e57-ff8b-09dd-aaeae0114612.png)

この状態は、以下のactiveの内容

```.css
.fv__hamburger.active span:nth-child(1) {
    top: 30px;
    left: 15px;
    transform: translateY(-6px) rotate(45deg);
    width: 18px;
}

.fv__hamburger.active span:nth-child(2) {
    opacity: 0;
}

.fv__hamburger.active span:nth-child(3) {
    top: 18px;
    left: 15px;
    transform: translateY(6px) rotate(-45deg);
    width: 18px;
}
```
が稼働中ということが言え、ボタンが✕となります。

### ボタンが✕の状態で押下した際に三本線にする。

次に、if条件が以下のとき、
```.js
    //こちらはボタンが✕の状態の処理
    $('#sp__bg').fadeOut(300);
    $(this).removeClass('active');

```

について確認していきます。

これは先程のと逆の対応をしていることが分かります。つまり以下の状態

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/c1304d03-1acf-d363-3be1-7294095cbc2d.png)
となっているため、

**$('#sp__bg').fadeOut(300);**
でフェードアウトを300msかけて行い、リンク一覧と背景を消しています。

同時にボタンを✕から三本線にする必要があるので、
**$(this).removeClass('active');**
でactiveがついていたものをremoveしてクラスを削除していることになります。結果、以下のように三本線に戻るようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/fd201cc6-37a2-e654-2690-28dc3504735f.png)

## リンクをクリックした際の動作
以下の状態で、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/eb9e2f0a-ffe1-3717-0652-26b186bc5cac.png)
リンクをクリックすると、本来であればそのページ内に遷移するようになります（遷移は今回実装はしません）が、現状はリンクをクリックしても「リンク一覧」の表示は消えない状態となっています。
このままだと、ページが遷移したとしても、上記の画像のままリンクが表示されたままになってしまいます。これを解決していきたいと思います。


今、html上では以下のようになっていますが、
```.html
    <!-- リンク表示 #sp_bg-->
    <div id="sp__bg">
      <ul class="nav__menu">
          <li class="nav__menu_item"><b>リンク一覧</b></li>
          <li class="nav__menu_item"><a href="#about">この農園について</a></li>
          <li class="nav__menu_item"><a href="#product">メニュー一覧</a></li>
          <li class="nav__menu_item"><a href="#info">お知らせ</a></li>
          <li class="nav__menu_item"><a href="#FAQ">FAQ</a></li>
          <li class="nav__menu_item"><a href="#access">アクセス</a></li>
          <li class="nav__menu_item"><a href="#inquiry">お問い合わせ</a></li>
      </ul>
    </div> 
```
ここで、各リストのリンク（ **.nav__menu_item** ）をクリックした際にフェードアウトして消したい、もしくは背景の白い部分をクリックしてもフェードアウトして消すことをしたいため、**#sp__bg**の部分をクリックしてもフェードアウトして消していこうと思います。


```js:script_jQ.js
$(function(){

//リンクを消す
	$('#sp__bg').hide();
	$('.fv__hamburger').click(function(){

        //※中身省略

	});
	
	//背景の白い部分、またはリンクをクリックした際に表示が消えるようにする
	$('#sp__bg, nav__menu_item').click(function(){
		$('#sp__bg').fadeOut(300);
		$('.fv__hamburger').removeClass('active');
	});

});

```

以下のように、リンクをクリックしたり、背景をクリックしてもフェードアウトしてリンク一覧が消えることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/aeac24d8-0465-79e5-48f0-6fbc6a2c39b5.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602679/5e28ca3d-ca48-4f50-79be-9f0d11c0e5f0.png)


これでハンバーガメニューボタンの実装が完了しました。



## コードまとめ

```html:index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="robots" content="noindex">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="js/jquery-3.7.0.min.js"></script>

    <title>ハンバーガーメニューの作り方</title>
    <link rel="stylesheet" href="css/reset.css">
    <link rel="stylesheet" href="css/style.css">

    <!--jQuery読み込み-->
    <script src="js/script_jQ.js"></script>
</head>
<body>




    <!--first view(fv)-->
    <header id="fv">
        <button class="fv__hamburger">
            <div>
                <span></span>
                <span></span>
                <span></span>
            </div>
        </button>
        <!-- スマートフォンに表示 #sp_bg-->
        <div id="sp__bg">
          <ul class="nav__menu">
              <li class="nav__menu_item"><b>リンク一覧</b></li>
              <li class="nav__menu_item"><a href="#about">この農園について</a></li>
              <li class="nav__menu_item"><a href="#product">メニュー一覧</a></li>
              <li class="nav__menu_item"><a href="#info">お知らせ</a></li>
              <li class="nav__menu_item"><a href="#FAQ">FAQ</a></li>
              <li class="nav__menu_item"><a href="#access">アクセス</a></li>
              <li class="nav__menu_item"><a href="#inquiry">お問い合わせ</a></li>
          </ul>
        </div> 
    </header>
  </body>
</html>
```


```.css
@charset "UTF-8";
/*ベース
*********************/
body {
  color: #475950;
  font-family: "Noto Sans JP", sans-serif;
}

a {
  text-decoration: none;
  color: #475950;
}



/*HEADER(first view)
*********************/
#fv {
  background-color: #00f;
  height: 667px;
  position: relative;
}

.fv__hamburger {
  cursor: pointer;
  position: fixed;
  border: 0px;
  top: 20px;
  right: 20px;
  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
  background: #c89932;
  height: 48px;
  width: 48px;
  border-radius: 50%;
  z-index: 10;
}

.fv__hamburger span {
  display: inline-block;
  transition: all 0.4s;
  position: absolute;
  left: 15px;
  height: 2px;
  border-radius: 2px;
  background: #eee;
  width: 18px;
}

 .fv__hamburger span:nth-child(1) {
  top: 18px;
}

.fv__hamburger span:nth-child(2) {
  top: 23px;
}

.fv__hamburger span:nth-child(3) {
  top: 28px;
}

  .fv__hamburger.active span:nth-child(1) {
    top: 30px;
    left: 15px;
    transform: translateY(-6px) rotate(45deg);
    width: 18px;
  }

  .fv__hamburger.active span:nth-child(2) {
    opacity: 0;
  }

  .fv__hamburger.active span:nth-child(3) {
    top: 18px;
    left: 15px;
    transform: translateY(6px) rotate(-45deg);
    width: 18px;
  }


/*スマートフォン　メニュー設定
************/


#sp__bg {
  position: fixed;
  left: 0;
  top: 0;
  height: 100%;
  width: 100%;
  background: rgba(255, 255, 255, 0.9);
  text-align: center;
  z-index: 1;
}

#sp__bg .nav__menu {
  padding-top: 61.6px;
  font-size: 16px;
  line-height: 23px;
  color: #475950;
} 

#sp__bg .nav__menu a {
  font-weight: 700;
}

#sp__bg .logo_sp {
  margin-bottom: 10.6px;
}

#sp__bg .nav__menu .logo3 {
  margin-bottom: 50px;
}

#sp__bg .nav__menu_item {
  margin-bottom: 16px;
}

#sp__bg .nav__menu_item:nth-child(1) {
  font-size: 26px;
  font-weight: 700;
  color:#c89932;
} 

```

```js:script_jQ.js
$(function(){

//リンクを消す
	$('#sp__bg').hide();
	$('.fv__hamburger').click(function(){

		//もし、ハンバーガーボタンに.activeクラスが付与されていた場合
		if($('.fv__hamburger').hasClass('active')){
			$('#sp__bg').fadeOut(300);
			$(this).removeClass('active');
		}else{
			$('#sp__bg').fadeIn(300);
			$(this).addClass('active');
		}

	});
	
	//リンクをクリックした際に表示が消えるようにする
	$('#sp__bg, nav__menu_item').click(function(){
		$('#sp__bg').fadeOut(300);
		$('.fv__hamburger').removeClass('active');
	});

});


```