トースト通知
ボタン操作後にふわっと現れ、数秒で自動消滅する通知。処理完了などの確認に使う。
プレビュー
操作クリック/タップで動きます。
仕様書
- 向く場面
- 保存・コピーなど判断を求めない結果通知
- 作業を止めずに成功を伝えたい操作
- 画面のどこにも紐づかない全体的な通知
- 避ける場面
- 必ず読ませたい内容や選択を求める内容
- 入力欄に紐づくエラー
- 読み返す手段が無い重要情報
- 構成要素
- トリガーボタン
- トースト
- メッセージ文
- 持っている状態
- 通常
- 押下中
- 成功
- キーボード
Tab でボタンへ、Enter/Space で通知を出す。トースト自体は操作対象でない
- 支援技術
role=status+aria-live=polite で中身の差し替えを読み上げ。要素は最初から DOM に置く。2.8 秒で自動消滅し、閉じるボタンは無い。reduced-motion で即時表示
- 動き
出現/退場 250ms ease(opacity+16px 上昇)。押下は opacity 150ms。reduced-motion で停止
デザインの要点
- トーストの要素は最初から DOM に置き、中身の文字だけ差し替える。後から要素ごと足すと aria-live が読まれない
- 出現は 16px 上へ滑らせながらフェード 250ms。位置を動かさずフェードだけだと「どこから来たか」が分からない
- 連打したらタイマーを clearTimeout で張り直す。前の消滅タイマーが残ると、新しい通知が 0.1 秒で消える
- pointer-events:none で本文の操作を邪魔しない。判断を求めないから、押せなくてよい
使いどころ
「操作は成功した、でも作業は止めたくない」場面に向く。保存、コピー、送信、削除の取り消しなど、結果を伝えるだけで判断を求めない通知が対象になる。画面の隅にふわっと出て自動で消えるので、ユーザーの作業を中断しない点が最大の利点。逆に、必ず読んでほしい内容や、選択を求める内容をトーストに載せるのは誤り。数秒で消えるため見落とされるうえ、消えた後に読み返す手段がない。そういう内容はダイアログか、画面内に留まるインラインのメッセージにする。エラーもトーストと相性が悪いことが多い。入力エラーは該当の入力欄のそばに出す方が直せる。トーストが適したエラーは「ネットワークが切れた」のような、画面のどこにも紐づかない全体的な通知に限られる。
仕組み
position: fixed で画面の隅に置いたコンテナに、通知要素を1つずつ追加していく。登場は transform: translateY() と opacity のトランジションで、少し下(または横)からスライドしながら現れる形にすると視線が自然に追える。消滅は setTimeout でクラスを外し、transitionend を待ってから要素を削除する。複数同時に出す場合はコンテナを flex の縦並びにして gap を取れば、追加した順に積み上がって位置計算が不要になる。同じ操作が連続したときは、新しいトーストを足すのではなく既存のものの文言と表示時間を更新する(あるいは「3件保存しました」とまとめる)方が画面が荒れない。表示時間は短い文言で3秒、少し長い文言で5秒前後が目安で、文字数に応じて可変にするのが親切。
実装の注意
z-index の競合が定番の落とし穴で、ヘッダーやモーダルの下に隠れて出ていることに気づけない。トーストは最前面に出す前提なので、プロジェクト全体で z-index の段階を決めておき、トーストはその最上位に置く。モバイルでは下部固定のナビゲーションやiOSのホームバーと重なりやすいため、env(safe-area-inset-bottom) を足した位置に出す。自動で消える設計は、ユーザーがちょうど文字を読んでいる最中に消えると不親切なので、ホバー中はタイマーを止める実装を入れるとよい。「元に戻す」ボタンを載せる場合は自動消滅と相性が悪く、消える前に押せなかったユーザーは操作を取り消せない。取り消しを提供するなら表示時間を長めに取り、同時に履歴などから後で取り消せる経路も用意しておく。
アクセシビリティ
トーストは画面を見ていないユーザーにも届く必要があるので、コンテナに role="status" と aria-live="polite" を付け、中身が書き換わったことをスクリーンリーダーに読ませる。重要度の高い通知でも aria-live="assertive" は読み上げを割り込ませてしまうため、本当に緊急なもの以外は polite に留めるのが作法。注意点として、live region は「最初から DOM にあるコンテナ」の中身が変わったときに読まれる。コンテナごと後から挿入すると読まれないことがあるので、空のコンテナを先に置いておく。自動で消える点も配慮が要る。読み上げや拡大表示を使うユーザーは読み終わるまでに時間がかかるため、prefers-reduced-motion ではスライドをやめてフェードだけにし、可能なら表示時間を延ばす、または閉じるボタンを常設して自分のタイミングで消せるようにする。
調整して使う
触るのは表示位置・表示時間・登場方向の3点。デスクトップは右下か右上、モバイルは画面下部(safe-area を足した位置)が定番で、操作した場所の近くに出すと視線移動が少ない。表示時間は短文3秒・長文5秒を基準に、1文字あたり50msを足す計算で可変にすると読み残しが減る。登場方向は「出てくる元」を意識して決めると自然で、下部に出すなら下から、上部なら上から入れる。種類別に左端の色帯(成功は緑、警告は橙、エラーは赤)を付けると一目で判別できるが、色だけに頼らずアイコンか語句も添える。複数同時に出す上限は3件程度にし、それを超えたら古いものから消すか「他2件」とまとめると画面が破綻しない。
コード(コピーして使えます)
<button class="toast-btn">通知を出す</button>
<div class="toast" role="status" aria-live="polite"></div>