Bootstrap5でオフキャンバス付きナビゲーションバーを実装する

この記事では、Bootstrap5でオフキャンバス付きのナビゲーションバーを実装する方法を記載しています。
約１年ほどBootstrapを使用しておりましたが、ハンバーガーメニューを開くと要素が上からスライドしてくることに不満を抱いていました。
今回、要素が横からスライドしてくるナビゲーションバーの実装方法を見つけたので、記録に残しておきたいと思い、記事を書きました。
【公式】--> https://getbootstrap.jp/docs/5.0/components/offcanvas/

完成図↓
<img width="375" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954196/35e31f8b-d31f-63e0-d19f-06ddda43e81e.png">

# 手順
1. [Bootstrapを使用する準備をする](#1-bootstrapを使用する準備をする)
2. [HTMLにナビゲーションバーのタグを追加する](#2-htmlにナビゲーションバーのタグを追加する)
3. [CSSを設定する](#3-cssを設定する)
4. [JavaScriptを設定する](#4-javascriptを設定する)
5. [完成](#5-完成)
6. [感想](#6-感想)

# 1. Bootstrapを使用する準備をする
```index.html
<!doctype html>
<html lang="en">

<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    <title>Hello, world!</title>
</head>

<body>
    <h1>Hello, world!</h1>

    <!--  Bootstrap Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
        crossorigin="anonymous"></script>
</body>

</html>
```
公式ではBootstrap5.2をインストールしていますが、
BootstrapのバージョンはBootstrap5以降であれば問題ないと思います。

# 2. HTMLにナビゲーションバーのタグを追加する
```index.html
<nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark" aria-label="メイン・ナビゲーション">
        <div class="container-fluid">
            <a class="navbar-brand" href="#">オフキャンバス</a>
            <button class="navbar-toggler p-0 border-0" type="button" id="navbarSideCollapse" aria-label="ナビゲーションの切替">
                <span class="navbar-toggler-icon"></span>
            </button>
    
            <div class="navbar-collapse offcanvas-collapse" id="navbarsExampleDefault">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        <a class="nav-link active" aria-current="page" href="#">ダッシュボード</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">通知</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">プロフィール</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">アカウント切替</a>
                    </li>
                    <li class="nav-item dropdown">
                        <a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown"
                            aria-haspopup="true" aria-expanded="false">ドロップダウン</a>
                        <ul class="dropdown-menu">
                            <li><a class="dropdown-item" href="#">リンク1</a></li>
                            <li><a class="dropdown-item" href="#">リンク2</a></li>
                            <li><a class="dropdown-item" href="#">リンク3</a></li>
                        </ul>
                    </li>
                </ul>
                <form class="d-flex" role="search">
                    <input class="form-control me-2" type="search" placeholder="検索" aria-label="検索">
                    <button class="btn btn-outline-success flex-shrink-0" type="submit">検索</button>
                </form>
            </div>
        </div>
    </nav>
```

buttonタグはBootstrapのJavascriptによって一定のブレイクポイントを下回ると出現するようになっています。
ブレイクポイントの切り替えはnavbar-expand-*で変更することができます。
| ブレイクポイント |クラス |デバイス |
|:-:|:-:|:-:|
|576px |.navbar-expand-sm |スマホ |
|768px |.navbar-expand-md |"|
|992px |.navbar-expand-lg |タブレット|
|1200px |.navbar-expand-xl |PC|
|1400px |.navbar-expand-xxl |"|

クラス名のoffcanvas-collapseが大事なポイントです。

# 3. CSSを設定する
```style.css
html,
body {
  overflow-x: hidden; /* 狭いデバイスでのスクロールを防止 */
}

body {
  padding-top: 56px;
}

@media (max-width: 991.98px) {
  .offcanvas-collapse {
    position: fixed;
    top: 56px; /* ナビバーの高さ */
    bottom: 0;
    left: 100%;
    width: 100%;
    padding-right: 1rem;
    padding-left: 1rem;
    overflow-y: auto;
    background-color: #343a40;
    transition: visibility .3s ease-in-out, -webkit-transform .3s ease-in-out;
    transition: transform .3s ease-in-out, visibility .3s ease-in-out;
    transition: transform .3s ease-in-out, visibility .3s ease-in-out, -webkit-transform .3s ease-in-out;
  }
  .offcanvas-collapse.open {
    visibility: visible;
    -webkit-transform: translateX(-100%);
    transform: translateX(-100%);
  }
}

.nav-scroller {
  position: relative;
  z-index: 2;
  height: 2.75rem;
  overflow-y: hidden;
}

.nav-scroller .nav {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: nowrap;
  flex-wrap: nowrap;
  padding-bottom: 1rem;
  margin-top: -1px;
  overflow-x: auto;
  color: rgba(255, 255, 255, .75);
  text-align: center;
  white-space: nowrap;
  -webkit-overflow-scrolling: touch;
}

.nav-underline .nav-link {
  padding-top: .75rem;
  padding-bottom: .75rem;
  font-size: .875rem;
  color: #6c757d;
}

.nav-underline .nav-link:hover {
  color: #007bff;
}

.nav-underline .active {
  font-weight: 510;
  color: #343a40;
}

.bg-purple {
  background-color: #6f42c1;
}
```
```index.html
<link rel="stylesheet" href="style.css">
```
ナビゲーションバーが上に固定されるため、bodyの上部をナビゲーションバーの高さだけ開けています。

# 4. JavaScriptを設定する
```script.js
(() => {
  'use strict'

  document.querySelector('#navbarSideCollapse').addEventListener('click', () => {
    document.querySelector('.offcanvas-collapse').classList.toggle('open')
  })
})()
```
```index.html
<script type="text/JavaScript" src="script.js"></script>
```

ナビゲーションバーに、クリックイベントを付与しています。

# 5. 完成
完成したソースコードは以下の通りです。
```index.html
<!doctype html>
<html lang="en">

<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    <!--  CSS  -->
    <link rel="stylesheet" href="style.css">

    <title>Hello, world!</title>
</head>

<body>
    <nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark" aria-label="メイン・ナビゲーション">
        <div class="container-fluid">
            <a class="navbar-brand" href="#">オフキャンバス</a>
            <button class="navbar-toggler p-0 border-0" type="button" id="navbarSideCollapse" aria-label="ナビゲーションの切替">
                <span class="navbar-toggler-icon"></span>
            </button>
    
            <div class="navbar-collapse offcanvas-collapse" id="navbarsExampleDefault">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        <a class="nav-link active" aria-current="page" href="#">ダッシュボード</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">通知</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">プロフィール</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">アカウント切替</a>
                    </li>
                    <li class="nav-item dropdown">
                        <a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown"
                            aria-haspopup="true" aria-expanded="false">ドロップダウン</a>
                        <ul class="dropdown-menu">
                            <li><a class="dropdown-item" href="#">リンク1</a></li>
                            <li><a class="dropdown-item" href="#">リンク2</a></li>
                            <li><a class="dropdown-item" href="#">リンク3</a></li>
                        </ul>
                    </li>
                </ul>
                <form class="d-flex" role="search">
                    <input class="form-control me-2" type="search" placeholder="検索" aria-label="検索">
                    <button class="btn btn-outline-success flex-shrink-0" type="submit">検索</button>
                </form>
            </div>
        </div>
    </nav>

    <div class="container">
        <h1>Hello, world!</h1>
    </div>

    <!--  JavaScript  -->
    <script type="text/JavaScript" src="script.js"></script>

    <!--  Bootstrap Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
        crossorigin="anonymous"></script>
</body>

</html>
```

```style.css
html,
body {
  overflow-x: hidden; /* 狭いデバイスでのスクロールを防止 */
}

body {
  padding-top: 56px;
}

@media (max-width: 991.98px) {
  .offcanvas-collapse {
    position: fixed;
    top: 56px; /* ナビバーの高さ */
    bottom: 0;
    left: 100%;
    width: 100%;
    padding-right: 1rem;
    padding-left: 1rem;
    overflow-y: auto;
    background-color: #343a40;
    transition: visibility .3s ease-in-out, -webkit-transform .3s ease-in-out;
    transition: transform .3s ease-in-out, visibility .3s ease-in-out;
    transition: transform .3s ease-in-out, visibility .3s ease-in-out, -webkit-transform .3s ease-in-out;
  }
  .offcanvas-collapse.open {
    visibility: visible;
    -webkit-transform: translateX(-100%);
    transform: translateX(-100%);
  }
}

.nav-scroller {
  position: relative;
  z-index: 2;
  height: 2.75rem;
  overflow-y: hidden;
}

.nav-scroller .nav {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: nowrap;
  flex-wrap: nowrap;
  padding-bottom: 1rem;
  margin-top: -1px;
  overflow-x: auto;
  color: rgba(255, 255, 255, .75);
  text-align: center;
  white-space: nowrap;
  -webkit-overflow-scrolling: touch;
}

.nav-underline .nav-link {
  padding-top: .75rem;
  padding-bottom: .75rem;
  font-size: .875rem;
  color: #6c757d;
}

.nav-underline .nav-link:hover {
  color: #007bff;
}

.nav-underline .active {
  font-weight: 510;
  color: #343a40;
}

.bg-purple {
  background-color: #6f42c1;
}
```

```script.js
(() => {
    'use strict'

    document.querySelector('#navbarSideCollapse').addEventListener('click', () => {
        document.querySelector('.offcanvas-collapse').classList.toggle('open')
    })
})()
```

完成図↓
![スクリーンショット 2022-11-03 212908.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954196/2144be28-6368-323a-4806-095a68aa2324.png)

# 6. 感想
Bootstrapは改めて本当に便利だなと思いました。
初心者でも簡単に質の良いレイアウトを作ることができるので、皆さんもぜひ活用してみてください。
ご覧いただきありがとうございました。