【Css】Mobile Slide Menu(スライドメニュー）を作ってみた

# 初めに
学習した内容をもとに、スマホのボタンを押すと画面がスライドしてメニューが表示される機能をCssやJavascriptを利用して作ってみました。

※内容に間違いなどがある場合はご指摘をよろしくお願いします。
※こちらの記事はあくまでも個人で学習した内容のoutputとしての記事になります。

# 完成形のイメージ
<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="redrabbit1104" data-slug-hash="gOmRvVd" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="moble_slide_menu">
  <span>See the Pen <a href="https://codepen.io/redrabbit1104/pen/gOmRvVd">
  moble_slide_menu</a> by redrabbit1104 (<a href="https://codepen.io/redrabbit1104">@redrabbit1104</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# Point
1.メニューボタンが格納されるheaderとメニューが配置されるmenuに分ける
2.menuはz-indexを使い、headerの下に来るように設定する
3.header部分をtransformを使い、左から右にずらしてスライドさせる

# Htmlで構造を作る
まず、mobile_containerという箱の中にslide_containerとmenuを配置します。

```html
<body>
    <section class="mobile_container">
        <div class="slide_container">   //スライドするheader要素が入るコンテナ
        </div>
        <nav class="menu">             //スライド後表示されるメニュー
        </nav>
    </section>
    <script src="menu_button.js"></script>
</body>
```
そしてslide_containerの中にheader要素を設け、前回作ったハンバーガーメニューボタンを配置させます。

https://qiita.com/redrabbit1104/items/f32f75c92b604c14e24e

menuにはlist形式でメニューが来るように、ulタグとliタグでメニューを作成します。
配置完了後の構造は次のようになります。

```html
<body>
    <section class="mobile_container">
        <div class="slide_container">
            <header class="header">
                <button class="menu_button">    //前回作成したmenuボタンを配置
                    <span></span>
                    <span></span>
                    <span></span>
                </button>
            </header>
        </div>
        <nav class="menu">                       //liタグでリスト形式のメニューを作る
            <ul>
                <li>
                    <a href=#">
                        <span>ホーム</span>
                    </a>
                </li>
                <li>
                    <a href=#">
                        <span>お知らせ</span>
                    </a>
                </li>
                <li>
                    <a href=#">
                        <span>サービス</span>
                    </a>
                </li>
                <li>
                    <a href=#">
                        <span>お問い合わせ</span>
                    </a>
                </li>
            </ul>
        </nav>
    </section>
    <script src="menu_button.js"></script>
</body>
```
複雑そうに見えますが、構造としては大きく2つに分けているだけなので意外とシンプルです。
![スクリーンショット 2021-05-26 9.10.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/966135/f7fcbcb8-c07c-58aa-85c8-4523e8419e31.png)

# scssの記述
cssで実装することは大きく分けて2つです。

- ❶スライド後表示されるメニュー部分をheader要素が入っているslide_containerの下に位置させる
- ❷slide_containerにアニメーション効果（左から右に移動する）を適用させる

まず、部品として使うmenu_buttonのスタイルをimportします。そして、body要素のmarginを０にして余白を消します。また、はみ出る部分をoverflow: hiddenを指定し隠します。こうすることによってスクロールバーやスワイプでスライドされなくなります。

https://kanoto.info/202001/679/

```sass
@import "menu_button.scss";

body {
  margin: 0;
  overflow: hidden;  //はみでる部分を隠す
}

```

ボタンの作り方(menu_button.scss)は前回の記事をご覧ください。

https://qiita.com/redrabbit1104/items/f32f75c92b604c14e24e

それからslide_containerのcssを記述します。headerの要素にflexboxを適用したいので、positionをrelativeにします。また、slide_containerとmenuは同じコンテキスト上にあるのでz-indexを指定できます。<b>slide_containerにz-indexを２にすることによってmenuよりも上に配置されることになります。

z-indexの前回作成した記事はこちら：
https://qiita.com/redrabbit1104/items/328003a9e90d5183ef9d
https://qiita.com/redrabbit1104/items/267922ade47ce741113e

```sass
//前略

.slide_container {
  position: relative;                        //relativeに指定
  background-color: rgb(108, 108, 196);
  height: 100vh;
  z-index: 5;　                              //z-indexを5にしmenuより上に配置させる
  .header {
    background-color: white;
    height: 100px;
    display: flex;
    justify-content: flex-start;
    align-items: center;
  }
}
```

次にmenu側のcssを記述します。positionをfixedにして画面左上を基準にします。また、leftを0にして左から離れた距離を0、topを100pxにして上から100px離れた地点に位置させます。

```sass
.menu {
  position: fixed;
  left: 0;
  top: 100px;
}
```

### slideアニメーションの適用
スライドさせるslide_containerにslideクラスが付与されたタイミングで右側に移動させたいので、
transformのtranslateXの値を300pxほど指定します。また、アニメーションを0.6秒間に渡って行われるようにしたいので、slide_containerにtransformを0.6sに指定します。これでスライドした時に滑らかな動きを見せてくれます。

```sass
.slide_container {
  position: relative;
  background-color: rgb(108, 108, 196);
  height: 100vh;
  z-index: 5;　　　　　　　　　　　　　　　　　　　　　　　　
  transition: transform 0.6s;   　　　　　 //追記
  &.slide {　　　　　　　　　　　　　　　　  //追記
    transform: translateX(300px);
  }
  .header {
    background-color: white;
    height: 100px;
    display: flex;
    justify-content: flex-start;
    align-items: center;
  }
}
```

# javascriptの記述

menu_buttonとslide_containerをquerySelectorで取得し変数に代入します。

```javascript
"use strict";

const btn = document.querySelector(".menu_button");
const container = document.querySelector(".slide_container");
```
ボタン(menu_button)をクリックした時にslide_containerにslideクラスを付けたり外したりしたいので、classListのtoggleメソッドでslideクラスを付与するように記述します。menu_buttonにopenクラスも同じ要領で記述します。

```javascript
//前略
btn.addEventListener('click', () => {
  btn.classList.toggle("open");
  container.classList.toggle("slide");
});
```
このままではマウスでクリックした時に瞬時に反応しますが、スマホなどで指でタッチした時は反応が遅くなり不自然です。そのため、スマホ画面に対応するためには'touchstart'イベントを指定する必要があります。これらのマウスクリックイベントとスマホタッチイベントをデバイスによって切り替える必要がありますので、三項演算子でwindow.ontouchstartが存在する（true)かどうかを判断してeventを'touchstart'か'click'かに切り分ける記述をします。

```javascript
const eventCondition = window.ontouchstart ? "touchstart" : "click";
```
このeventConditionをaddEventListenerの'click'の代わりに代入してあげます。こうすることによって画面に応じたイベントの切り替えができます。

```javascript
"use strict";

//前略
const eventCondition = window.ontouchstart ? "touchstart" : "click";  //追記
btn.addEventListener(eventCondition, () => {     //'click'をeventConditionに修正
btn.classList.toggle("open");
container.classList.toggle("slide");
});
```

#参考サイト
https://freefielder.jp/blog/2014/12/javascript-touch-screen.html
https://qiita.com/7968/items/812d6a21fc4dd9ae9c75
https://developer.mozilla.org/ja/docs/Web/CSS/transform
https://kanoto.info/202001/679/