Bootstrap 4.5 で Toasts を焼いてみた

Toastってなに？　Macに標準搭載の英和辞書で調べてみると、

> Can I have some toast and a cup of coffee?
> トーストとコーヒーを1杯頂けますか

なんて例文が表示されます。紛れもなくあの「トースト」。

この用語、「一般的だろ」とか、「普通に知ってる」とかいう開発者の方はちょっと待ってください。誤解してます。

私は、Windows, ｍacOS, iOS, Androidの開発をやってきましたが、この用語が出てくるのは、**Android**開発だけです。

## Toasts は、「通知」のこと

もうふつうに、Notification でいいじゃない。

たぶんですけど、トースターからパンが飛び跳ねるみたいなのをイメージして付けられた名前でしょうか（横から出てくることが多いのに）。

ウチは、オーブントースターで焼くので正直これでも実感が湧かないです。ふつう一家に一台、トースターありますか。パン焼くだけに特化したマシンですよね。

## Bootstrap の Toasts を焼く（もとい、表示する）

基本的に Bootstrap は、CSSなどをあまり意識することなく簡単にウェブサイトデザインを作れるというところが売り、と自分は解釈していますので、当然この Toasts もデザイン不要で即座にデフォルト表示できます。

ただし、動的なキッカケが必要となりますので、JavaScript での制御は必要です。

まずは動作に必要な Bootstrap を読み込みます。

```html:toast.html
<link rel="stylesheet" href="css/bootstrap.min.css">
<script src="js/jquery-3.5.1.min.js"></script>
<script src="js/bootstrap.min.js"></script>
```

古い記事などを見ると、たまに「`popper.js` も必要」とか書いてある例が見受けられますが、ver.4.5 時点では、`bootstrap.min.js` 単体を読み込めばイケるようです。

HTML ファイルのどこかに、表示したい Toast の記述を行います。Bootstrap の[公式ドキュメント](https://getbootstrap.jp/docs/4.5/components/toasts/)に従って書けば、このような感じです。

```html:toast.html
<div class="toast" id="myToast">
  <div class="toast-header">
    <strong class="mr-auto"><i class="far fa-envelope"></i>清少納言より</strong>
    <small>about 1,050 years ago</small>
    <button type="button" class="ml-2 mb-1 close" data-dismiss="toast">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="toast-body">
    <div>春はあけぼの。やうやう白くなりゆく山際、少し明かりて、紫だちたる雲の細くたなびきたる。<br />
    <a href="#">Click here!</a></div>
  </div>
</div>
```

この `<div>` ブロックは、クラスの `.toast` の指定がされていれば、通常状態では表示されません（内部的には `opacity: 0` になっています）。

実際にこれを表示する JavaScript は、以下の通りです。

```javascript
$("#myToast").toast('show');
```

![toast01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30945/926ca9d7-dddb-1dc4-0af8-dad28ba9c3c9.png)
[DEMO](https://codepen.io/hibara/pen/LYRpZze)

ただ、これを表示すると、一瞬で消えてしまうと思います。奥ゆかしくて良いじゃないの、と思う方もいるかもしれませんが、短すぎやしませんか。なんかのクイズみたいになってます。これは実際、表示するデフォルト時間が、`500(ms)` に設定されているからです。

なので、もう少し表示時間を延ばすために、`option` の `delay` を設定してやる必要があります。

```javascript
$("#myToast").toast({ delay: 3000 }).toast('show');
```

[DEMO](https://codepen.io/hibara/pen/eYdpdmG)

これで、通知「らしく」なったと思います。

## 表示場所は CSS で設定しなければならない

先ほど、Bootstrap は CSS をほとんど意識する必要なく使えると書きましたが、表示位置は指定する必要があります。

タグに直接 `style` 指定を書いても良いのですが、HTML ファイルなり、CSS なりに書いてしまいましょう。

```css:style.css
#myToast {
  position: absolute;
  top: 0;
  right: 0;
}
```

実は、`bootstrap.css` に、`.toast` を定義している箇所があるので、そこへ付け加えても良いかもしれません。

```css:bootsrap.css
.toast {
  -ms-flex-preferred-size: 350px;
  flex-basis: 350px;
  max-width: 350px;
  font-size: 0.875rem;
  background-color: rgba(255, 255, 255, 0.85);
  background-clip: padding-box;
  border: 1px solid rgba(0, 0, 0, 0.1);
  box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);
  opacity: 0;
  border-radius: 0.25rem;
  /*** 以下を追加 ***/
  position: absolute;
  top: 0;
  right: 0;
}
```

## Toast のデフォルト設定はなぜか半透明で、ベタの白色

上の `bootstrap.css` を見れば分かるとおり、`Toast` の下地は半透明（`0.85`）に設定されています。下の表示を邪魔しない、という意図なのかもしれませんが、`0.85` って微妙な数値ですよね。先にも言いましたが、Bootstrap は、CSS などをあまり意識することなく簡単にウェブサイトデザインを作れるというところ（略

ついでに言うと、下地はベタの白色（255, 255, 255）なので、もし `Toast` の色を変えたいという場合は、`background-color` をいじると良いでしょう。

## さらに、Navbar を固定（Fixed）で置くと下に潜ってしまう

「通知」って一番上に来るものではないの？　という素朴な疑問が生まれてしまいますが、実際そうなります。

```html:toast.html
<nav class="navbar fixed-top navbar-dark bg-dark text-light">
  <a class="navbar-brand" href="#">Fixed top</a>
  <button class="btn btn-outline-success my-2 my-sm-0 show-toast" type="submit">トーストを焼く</button>
</nav>
```

このナビゲーションバーを置いた状態で、Toast を表示すると、なんとも物悲しい感じになります。

![toast02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30945/e829a34e-9d43-fd55-ab36-a9af18e75347.png)

これを防ぐには、`z-index` を設定しましょう。

```css:style.css
#myToast {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 1040; /* 一番上！ */
}
```

`z-index: 1040` は、やり過ぎですか。それも半端な数。そうですか。そうですよね。

でも、`bootstrap.css` の、`.fixed-top` の定義内容を確認してみてください。

```css:bootstrap.css
.fixed-top {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  z-index: 1030;
}
```

なに、`1030` って。最初は、「1000だとユーザーが他で設定しそうだし、1010だと中途半端だから、1030くらいにしておくか」的な感じに適当で決めてるだろうと思い込んでいましたが、申し訳ありません。これはどうやら、Bootstrap の仕様できっちり決められているようです。

## Bootstrap における Z-index

詳しくは以下のページに明記されております。
<https://getbootstrap.jp/docs/4.5/layout/overview/#z-index>

```
$zindex-dropdown:          1000 !default;
$zindex-sticky:            1020 !default;
$zindex-fixed:             1030 !default;
$zindex-modal-backdrop:    1040 !default;
$zindex-modal:             1050 !default;
$zindex-popover:           1060 !default;
$zindex-tooltip:           1070 !default;
```
ここでは、navbar が、`$zindex-fixed` にあたるので、`1030` が設定されているようです。

というわけで最終的には、以下のようになりました。

![toast03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30945/f032c528-0e84-e684-4378-e56890a4b669.png)

HTMLファイルとして以下の内容を貼り付けてブラウザで開けば、ローカルでも確認できます。一応、ソースコードの下に「DEMO」もあるので、そちらでも確認できます。

```html:toast.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <title>Bootstrap 4 Toasts</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">
  <style type="text/css">
    #myToast {
      position: absolute;
      top: 0;
      right: 0;
      z-index: 1040;
    }
    button#burn {
      margin-left: 10px;
      margin-top: 80px;
    }
  </style>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>  <script>
    $(document).ready(function(){
      $(".show-toast").click(function(){
        // $("#myToast").toast('show');
        $("#myToast").toast({ delay: 3000 }).toast('show');
      });
    });
  </script>
</head>
<body>

<!-- Toast -->
<div class="toast" id="myToast">
  <div class="toast-header">
    <strong class="mr-auto"><i class="far fa-envelope"></i>清少納言より</strong>
    <small>about 1,050 years ago</small>
    <button type="button" class="ml-2 mb-1 close" data-dismiss="toast">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="toast-body">
    <div>春はあけぼの。やうやう白くなりゆく山際、少し明かりて、紫だちたる雲の細くたなびきたる。<br />
    <a href="#">Click here!</a></div>
  </div>
</div>

<nav class="navbar fixed-top navbar-dark bg-dark text-light">
  <a class="navbar-brand" href="#">Fixed top</a>
</nav>

<button id="burn" type="button" class="btn btn-primary show-toast">トーストを焼く</button>

</body>
</html>
```

[DEMO](https://codepen.io/hibara/pen/XWjmjmV)

以上です。