オーガニック・シェイプ トースト通知(ブロブ縁カード)

様式名: オーガニック・シェイプ / トースト通知

トースト通知ブロブ自動消滅ライブリージョン
⧉ 別タブで開く

「壊れた例」を押すと、この様式が成立しなくなる条件を実物で見られます。

特徴 — なぜ効くか

  • border-radius の8値指定で角を非対称に崩し、通知カードにも直線・正円を避けた柔らかさを持たせる。17のフッターと同じ手法をUIパーツの縁に応用する
  • 種類(成功・エラー・情報)ごとに淡いパステルの地色を敷き、アイコン・見出しは濃色で常時AAを確保する。パステルの縁だけを識別手段にしない
  • 自動で消える通知という性質上、この様式特有の課題(曲線で境界が曖昧)よりも先に、通知全般に共通する時間制限の課題(WCAG 2.2.1)が前面に出る
  • 17で『曲線は要素の境界を曖昧にする』と書いたのと同型の罠が、閉じるボタンの当たり判定にも起きる。見た目の丸みに合わせて当たり判定まで削ると押しにくくなる

実装メモ — 踏んだ罠

  • カードは border-radius の8値指定(例 30px 42px 28px 46px / 40px 26px 44px 30px)で軽く崩す。17ほど極端にすると通知の輪郭が読み取りにくくなるため、崩し幅は控えめにする
  • 地色はパステルの『ベタ塗り』ではなく極薄の『ウォッシュ』(例 成功 #eef7f1)にし、見出し・アイコンは濃色にする。17と同様、装飾色の彩度と文字色の濃さは別軸で決める
  • 【自分で実測した数値】成功ウォッシュ #eef7f1 の上で見出し #243038 は 12.35:1、アイコン緑 #1f6b4a は 5.89:1。エラーウォッシュ #fbeced 上でアイコン赤 #9c2b34 は 6.52:1。情報ウォッシュ #eaf1fb 上でアイコン青 #375f8a は 5.83:1。いずれもAA(4.5:1)を確保している
  • role="status"(成功・情報)/role="alert"(エラー、暗黙に aria-live="assertive")を必ず付ける。付けないと通知の見た目がどれだけ目立っても、スクリーンリーダー利用者には一切伝わらない(demo_bad.html で実演)
  • 自動消滅のタイマーは :hover と :focus-within で必ず一時停止する(WCAG 2.2.1『タイミング調整可能』)。カーソルを乗せている間・キーボードでフォーカスしている間に消えると、読み終える前に情報が失われる
  • 閉じるボタンは視覚上のブロブの丸みに合わせて小さくしない。padding で44px相当の当たり判定を確保し、見た目の縁と操作領域を分離する

使いどころ / 使ってはいけない場面

壊れる条件

コントラスト実測

対象文字色背景実効背景判定
見出し(成功ウォッシュ上)#243038#eef7f1#eef7f112.35:1AA 合格
アイコン緑(成功ウォッシュ上)#1f6b4a#eef7f1#eef7f15.89:1AA 合格
アイコン赤(エラーウォッシュ上)#9c2b34#fbeced#fbeced6.52:1AA 合格
アイコン青(情報ウォッシュ上)#375f8a#eaf1fb#eaf1fb5.83:1AA 合格
本文(成功ウォッシュ上)#4a5a63#eef7f1#eef7f16.55:1AA 合格

アクセシビリティ

スマホへの落とし方

ブラウザ対応

関連するパーツ

コードを見る
<!doctype html>
<html lang="ja"><head><meta charset="utf-8"><title>オーガニック・シェイプ トースト通知 デモ</title><style>
*{box-sizing:border-box;margin:0;padding:0}
:root{
  --page:#edf0ee;
  --ink:#243038;
  --sub:#4a5a63;
  --ok-bg:#eef7f1;   --ok:#1f6b4a;
  --err-bg:#fbeced;  --err:#9c2b34;
  --info-bg:#eaf1fb; --info:#375f8a;
}
body{background:var(--page);color:var(--ink);min-height:340px;padding:26px 28px;
  font-family:system-ui,-apple-system,"Hiragino Kaku Gothic ProN","Yu Gothic",sans-serif}
h3{font-size:15px;letter-spacing:.02em;margin-bottom:4px}
.lead{font-size:12px;color:var(--sub);line-height:1.8;max-width:34em;margin-bottom:20px}

.stack{display:flex;flex-direction:column;gap:14px;max-width:26em}
.toast{position:relative;display:flex;gap:12px;align-items:flex-start;padding:14px 40px 14px 16px;
  /* border-radiusの8値指定で角を非対称に崩す。17より崩し幅は控えめ(通知の輪郭は保つ) */
  border-radius:30px 42px 28px 46px / 40px 26px 44px 30px;
  box-shadow:0 6px 18px rgba(36,48,56,.08)}
.toast.ok{background:var(--ok-bg)}
.toast.err{background:var(--err-bg)}
.toast.info{background:var(--info-bg)}
.icon{flex:none;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-size:14px;font-weight:800;color:#fff}
.toast.ok .icon{background:var(--ok)}
.toast.err .icon{background:var(--err)}
.toast.info .icon{background:var(--info)}
.body h4{font-size:13px;margin-bottom:3px}
.toast.ok h4{color:var(--ok)}
.toast.err h4{color:var(--err)}
.toast.info h4{color:var(--info)}
.body p{font-size:12px;color:var(--sub);line-height:1.6}
/* 閉じるボタン:視覚サイズは20pxでも、当たり判定はpaddingで44px相当を確保する。
   ブロブの丸みに合わせて当たり判定まで削らない */
.close{position:absolute;top:6px;right:6px;width:44px;height:44px;border:0;background:none;
  color:var(--sub);font-size:15px;cursor:pointer;display:flex;align-items:center;justify-content:center}
.close:hover{color:var(--ink)}
.close:focus-visible{outline:2px solid var(--ink);outline-offset:-2px;border-radius:50%}
/* 自動消滅の残り時間バー。hoverまたはfocus-withinで一時停止する(WCAG 2.2.1) */
.timer{position:absolute;left:16px;right:40px;bottom:6px;height:3px;border-radius:999px;background:rgba(0,0,0,.08);overflow:hidden}
.timer::after{content:"";display:block;height:100%;width:100%;transform-origin:left;
  animation:shrink 6s linear forwards}
.toast.ok .timer::after{background:var(--ok)}
.toast.err .timer::after{background:var(--err)}
.toast.info .timer::after{background:var(--info)}
.toast:hover .timer::after,.toast:focus-within .timer::after{animation-play-state:paused}
@keyframes shrink{from{transform:scaleX(1)}to{transform:scaleX(0)}}
@media (prefers-reduced-motion:reduce){.timer::after{animation:none;transform:scaleX(1)}}

.note{margin-top:20px;font-size:11px;line-height:1.75;color:var(--sub);max-width:36em}
.note code{background:#fff;padding:1px 5px;border-radius:3px;font-family:ui-monospace,Consolas,monospace}
</style></head><body>
<h3>消える前に読めるか、読み上げられるか</h3>
<p class="lead">通知の縁は8値指定で軽く崩し、地色は淡いウォッシュ、見出し・アイコンは濃色で常時AAを確保する。自動消滅はホバー・フォーカス中は止まる。</p>

<div class="stack" aria-label="通知">
  <div class="toast ok" role="status">
    <div class="icon" aria-hidden="true">✓</div>
    <div class="body"><h4>保存しました</h4><p>変更内容はすべて反映されています。</p></div>
    <button class="close" type="button" aria-label="この通知を閉じる">×</button>
    <div class="timer" aria-hidden="true"></div>
  </div>
  <div class="toast err" role="alert">
    <div class="icon" aria-hidden="true">!</div>
    <div class="body"><h4>送信に失敗しました</h4><p>通信環境を確認してもう一度お試しください。</p></div>
    <button class="close" type="button" aria-label="この通知を閉じる">×</button>
    <div class="timer" aria-hidden="true"></div>
  </div>
  <div class="toast info" role="status">
    <div class="icon" aria-hidden="true">i</div>
    <div class="body"><h4>新しいお知らせがあります</h4><p>アップデート内容をご確認ください。</p></div>
    <button class="close" type="button" aria-label="この通知を閉じる">×</button>
    <div class="timer" aria-hidden="true"></div>
  </div>
</div>

<p class="note">
  <code>role="status"</code>/<code>role="alert"</code> でスクリーンリーダーに通知内容を届け、
  <code>:hover</code>・<code>:focus-within</code> でタイマーを一時停止する(WCAG 2.2.1)。
  種類の違いはアイコン形状とテキストで示し、色(縁のウォッシュ)だけに頼らない。
</p>
</body></html>
出典・参考: 自作の再現実装。有機的な曲線の成立条件は17_organic_footerの実測知見を踏襲。自動消滅とタイミングの配慮は WCAG 2.2.1 https://www.w3.org/WAI/WCAG21/Understanding/timing-adjustable.html (一次情報)。role=alert/status の使い分けは https://www.w3.org/WAI/ARIA/apg/practices/alert/ (一次情報、2026-07-30閲覧)。コントラスト値は当方で実測。