第19回 JavaScript アニメーションによるモーダルサイドバー（translateX）

# はじめに
Webサイトによく出てくるサイドバーを作りたいと思います。
第18回で作成したサイドバーの別パターンです。

# 今回実施する内容
今回は、Webでよく出てくるサイドバーを`anitemate`と`translateX`を使用して作成したいと思います。
今回のサイドバーはモーダルにします。モーダルなため、サイドバー以外の画面はリンクなどを無効にします。サイドバー以外をクリックした場合はサイドバーが閉じるようにします。
また、サイドバー内にもメニューアイコン（ハンバーガーアイコン）を追加します。
以下のような感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/befe4989-f02d-cdee-538d-5d1f2df6104b.png)

なお、[第18回 JavaScript アニメーションによるサイドバー（translateX）](https://qiita.com/Mount/items/c04d0f778554d898d90e)と同じ部分は説明を割愛します。

![sidebar2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/4495f7ff-c3fd-ed97-c55c-1a5183cdd5c7.gif)


# ソースコード(Git Hub)
https://github.com/Build-Mount/JS_19_sidebar2

# 環境
OS: Windows 11 JP (64bit)
バージョン 125.0.2535.51 (公式ビルド) (64 ビット)

# 参考
- [Element: animate() メソッド](https://developer.mozilla.org/ja/docs/Web/API/Element/animate)
- [translateX()](https://developer.mozilla.org/ja/docs/Web/CSS/transform-function/translateX)
- [第13回 JavaScript アニメーションによる拡大・縮小（animate版）](https://qiita.com/Mount/items/22c1fc1b9577c44e695c)
- [第17回 JavaScript 「三」、「✕」みたいなメニューアイコン作成（CSSです）](https://qiita.com/Mount/items/79241e77da356b884b23)
- [第18回 JavaScript アニメーションによるサイドバー（translateX）](https://qiita.com/Mount/items/c04d0f778554d898d90e)
- [DOMTokenList: toggle() メソッド](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/toggle)

# 用語

# サイドバーを作る
[第18回 JavaScript アニメーションによるサイドバー（translateX）](https://qiita.com/Mount/items/c04d0f778554d898d90e)をベースにサイドバーを作成します。

<details>
<summary>sideBar2_translateX.html</summary>

```html:sideBar2_translateX.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>sideBar2</title>
    <link rel="stylesheet" href="sideBar2_translateX.css" type="text/css">
    <script src="sideBar2_translateX.js" defer></script>
</head>
<body>
    <div id="menuIcon" class="menuIcon">
        <span class="bar barTop"></span>
        <span class="bar barMiddle"></span>
        <span class="bar barBottom"></span>
    </div>
    <div id="sideBar">
        <div id="menuIcon2" class="menuIcon">
            <span class="bar barTop"></span>
            <span class="bar barMiddle"></span>
            <span class="bar barBottom"></span>
        </div>
        <div id="menuList">
            <div id="home">ホーム</div>
            <div id="mypage">マイページ</div>
            <div id="channel">チャンネル</div>
        </div>
    </div>
    <div id="cover" class="cover"></div>

    <div id="main"><a href="">あいうえお</a></div>

</body>
</html>
```
</details>

<details>
<summary>sideBar2_translateX.js</summary>

```javascript:sideBar2_translateX.js
let offset = -160;
/** side barの表示・非表示設定 */
document.getElementById("menuIcon").addEventListener("click", () => {
    showSideBar();
});

document.getElementById("menuIcon2").addEventListener("click", () => {
    showSideBar();
});

document.getElementById("cover").addEventListener("click", () => {
    showSideBar();
});


function showSideBar() {
    document.getElementById("cover").classList.toggle("coverVisible");
    offset = -offset;
    const animation = document.getElementById("sideBar").animate(
        [
            {   transform: `translateX(${offset}px)`    }
        ],
        {
            duration: 300,
            fill: "forwards"
        },
    );
}
```
</details>

<details>
<summary>sideBar2_translateX.css</summary>

```css:sideBar2_translateX.css
/* menu Icon用開始 */
.menuIcon {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 48px;
  height: 48px;
}

.menuIcon:hover {
  background-color: #999;
  border-radius: 50%;
}

.bar {
  position: absolute;
  left: 14px;
  width: 20px;
  height: 2px;
  background-color: #333;
}

.barTop {
  top: 14px;
}

.barMiddle {
  top: 23px;
}

.barBottom {
  top: 32px;
}
/* menu Icon用終了*/

/* side Bar用開始 */
#sideBar {
  position: absolute;
  bottom: 0px;
  left: -160px;
  width: 160px;
  height: 100%;
  border: 0px solid gray;
  z-index: 99;
  background-color: #fff;
}

#menuList {
  position: absolute;
  top: 60px;
}

.cover {
  position: absolute;
  top: 0px;
  left: 0px;
  width: 100%;
  height: 100%;
  background-color: gray;
  visibility: hidden;
  opacity: 0.3;
  z-index: 98;
}

.coverVisible {
  visibility: visible;
}

#main {
  position: absolute;
  top: 60px;
  left: 200px;
  font-size: 2em;
}
```
</details>

## sideBar2_translateX.htmlの説明
第18回に作成したサイドバーと同様のものをメニューアイコンにも配置するため、メニューアイコンの`<div id="menuIcon">`要素に、`class="menuIcon"`を追加します。
サイドバーの本体となる`<div id="sideBar">`要素内にもメニューアイコンを埋め込みました。メニューアイコンのソースは、`id="menuIcon2"`を除きサイドバーの外にあるものと同じです。

`<div id="cover" class="cover"></div>`は、サイドバーを表示したときにサイドバー以外をグレーアウトするために追加しました。

`<div id="main"><a href="">あいうえお</a></div>`はモーダルサイドバーには関係はなく、サイドバーを表示中にサイドバー以外の画面が無効になっていることを確認するために、ダミーのハイパーリンクを作成しました。

## sideBar2_translateX.jsの説明
`addEventListener`で、`div`要素の`id="menuIcon"`、`id="menuIcon2"`、および、`id="cover"`に`showSIdeBar()`を実行するようにします。
- `menuIcon`は最初のメニューアイコン
- `menuIcon`はサイドバー内のメニューアイコン
- `cover`はサイドバー表示時のサイドバー以外の部分

です。

`function showSideBar()`は、前回からの差分は、以下です。
```javascript
document.getElementById("cover").classList.toggle("coverVisible");
```
`<div id="cover">`にCSSの`coverVisible`クラスの追加と削除をする（トグルする）ようにしています。
`<div id="cover>"には`class="cover"`クラスが設定されており、このクラスでは、`visibility: hidden`を設定しており、最初は非表示に設定されています。
これをトグルしてクラスが追加された場合は、`<div id="cover">`を表示し、削除された場合に、`div`要素の`id="cover"`を非表示にします。

## sideBar2_translateX.cssの説明
第18回には、IDセレクターとしてしていた`#menuIcon`、`#menuIcon:hover`は、クラスセレクター`.menuIcon`、`.menuIcon:hover`に変更しました。中身は同じです。

サイドバーは、中身は第18回とほぼ同じですが、z-indexは99に設定し、最前面にしました。
```css
#sideBar {
  position: absolute;
  bottom: 0px;
  left: -160px;
  width: 160px;
  height: 100%;
  border: 0px solid gray;
  z-index: 99;
  background-color: #fff;
}
```

また、`.cover`クラスを設定しました。
この`.cover`クラスでは画面一杯に覆うように設定（`top: 0px; left: 0px; width: 100%; height: 100%`）し、背景色を灰色にし、半透明にして透過（`opacity: 0.3`）にしました。
z-indexは98を設定し、サイドバーより背面にしました。
```css
.cover {
  position: absolute;
  top: 0px;
  left: 0px;
  width: 100%;
  height: 100%;
  background-color: gray;
  visibility: hidden;
  opacity: 0.3;
  z-index: 98;
}
```

`.coverVisible`クラスは、要素を表示するためだけのクラスです。
このクラスを`toggle`することで、`<div id="cover">`の表示・非表示を切り替えます。
```css
.coverVisible {
  visibility: visible;
}
```

# おわりに
第18回に作成したサイドバーよりももう少し機能や見た目を追加し、よさげに見えるように改善しました。
サイドバーの作成については概ね期待するものが作れたように思います。