完了・受信箱ゼロ

チェックマークが描かれ、紙吹雪が漂う「すべて完了」の空状態。ボタンを押すたびに紙吹雪が弾け、達成感を演出します。受信箱ゼロの表示に最適です。

#css#svg#empty

ライブデモ

コード

HTML
<!-- 空状態: 完了・受信箱ゼロ。チェックが描画され、紙吹雪が漂う。CTAクリックで紙吹雪がもう一度弾ける -->
<main class="ead-card">
  <svg class="ead-illus" viewBox="0 0 200 170" width="168" height="143" role="img" aria-label="すべてのタスクが完了したことを示す、チェックマークと紙吹雪のイラスト">
    <g class="ead-confetti" data-confetti aria-hidden="true">
      <rect class="ead-piece ead-piece--1" x="28" y="38" width="10" height="10" rx="2"></rect>
      <circle class="ead-piece ead-piece--2" cx="170" cy="44" r="6"></circle>
      <rect class="ead-piece ead-piece--3" x="152" y="120" width="9" height="9" rx="2"></rect>
      <circle class="ead-piece ead-piece--4" cx="32" cy="122" r="5"></circle>
      <rect class="ead-piece ead-piece--5" x="96" y="16" width="8" height="8" rx="2"></rect>
      <circle class="ead-piece ead-piece--6" cx="158" cy="86" r="4.5"></circle>
    </g>
    <g class="ead-badge-group">
      <circle class="ead-badge-ring" cx="100" cy="82" r="40"></circle>
      <path class="ead-check" d="M82 82 L94 94 L120 66"></path>
    </g>
  </svg>

  <h2 class="ead-title">すべて完了しました!</h2>
  <p class="ead-desc">新しい通知はありません。今のうちに、少し休憩してくださいね。</p>

  <button class="ead-cta" type="button" data-cta>受信箱に戻る</button>
</main>
CSS
/* 空状態: 完了・受信箱ゼロ */
* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 32px 20px;
  font-family: "Hiragino Sans", "Yu Gothic UI", "Segoe UI", system-ui, -apple-system, sans-serif;
  background:
    radial-gradient(circle at 18% 16%, rgba(52, 211, 153, .16) 0%, transparent 46%),
    radial-gradient(circle at 86% 84%, rgba(253, 224, 71, .2) 0%, transparent 50%),
    #f7fdf9;
  color: #065f46;
}

.ead-card {
  width: 100%;
  max-width: 380px;
  background: #ffffff;
  border-radius: 24px;
  padding: 40px 32px 34px;
  text-align: center;
  box-shadow: 0 24px 60px -24px rgba(5, 150, 105, .24), 0 2px 8px rgba(6, 95, 70, .06);
  border: 1px solid rgba(52, 211, 153, .14);
}

.ead-illus { display: block; margin: 0 auto 8px; overflow: visible; }

.ead-badge-group {
  transform-box: fill-box;
  transform-origin: center;
  animation: ead-breathe 3s ease-in-out infinite;
}
@keyframes ead-breathe {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.04); }
}
.ead-badge-ring { fill: #d1fae5; stroke: #10b981; stroke-width: 4; }
.ead-check {
  fill: none;
  stroke: #047857;
  stroke-width: 8;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 56;
  stroke-dashoffset: 56;
  animation: ead-draw .6s .15s cubic-bezier(.22,1,.36,1) forwards;
}
@keyframes ead-draw { to { stroke-dashoffset: 0; } }

/* 漂う紙吹雪(アイドル) */
.ead-piece {
  transform-box: fill-box;
  transform-origin: center;
  animation: ead-float 3.6s ease-in-out infinite;
}
.ead-piece--1 { fill: #fbbf24; animation-delay: 0s; }
.ead-piece--2 { fill: #60a5fa; animation-delay: .5s; }
.ead-piece--3 { fill: #f472b6; animation-delay: 1s; }
.ead-piece--4 { fill: #a78bfa; animation-delay: 1.4s; }
.ead-piece--5 { fill: #34d399; animation-delay: .8s; }
.ead-piece--6 { fill: #fb923c; animation-delay: 1.8s; }
@keyframes ead-float {
  0%, 100% { transform: translateY(0) rotate(0deg); opacity: .55; }
  50% { transform: translateY(-8px) rotate(50deg); opacity: 1; }
}

/* クリックで再生する紙吹雪バースト */
.ead-piece.is-bursting { animation: ead-burst .7s cubic-bezier(.22,1,.36,1); }
@keyframes ead-burst {
  0% { transform: translate(0, 0) scale(1) rotate(0deg); opacity: 1; }
  70% { opacity: 1; }
  100% { transform: translate(var(--bx, 10px), var(--by, -18px)) scale(.6) rotate(160deg); opacity: 0; }
}
.ead-piece--1.is-bursting { --bx: -18px; --by: -16px; }
.ead-piece--2.is-bursting { --bx: 20px; --by: -14px; }
.ead-piece--3.is-bursting { --bx: 16px; --by: 18px; }
.ead-piece--4.is-bursting { --bx: -20px; --by: 16px; }
.ead-piece--5.is-bursting { --bx: 6px; --by: -22px; }
.ead-piece--6.is-bursting { --bx: 18px; --by: -6px; }

.ead-title { margin: 6px 0 10px; font-size: 21px; font-weight: 700; color: #065f46; }
.ead-desc { margin: 0 0 24px; font-size: 14.5px; line-height: 1.7; color: #4d7c6f; }

.ead-cta {
  appearance: none;
  border: none;
  cursor: pointer;
  padding: 13px 30px;
  font-size: 15px;
  font-weight: 600;
  color: #fff;
  background: linear-gradient(135deg, #34d399 0%, #059669 100%);
  border-radius: 999px;
  box-shadow: 0 12px 26px -10px rgba(5, 150, 105, .5);
  transition: transform .25s cubic-bezier(.22,1,.36,1), box-shadow .25s ease;
}
.ead-cta:hover { transform: translateY(-2px); box-shadow: 0 16px 32px -10px rgba(5, 150, 105, .6); }
.ead-cta:active { transform: translateY(0); }

@media (prefers-reduced-motion: reduce) {
  .ead-badge-group, .ead-piece { animation: none !important; }
  .ead-check { stroke-dashoffset: 0; animation: none !important; }
}
JavaScript
// 空状態: 完了・受信箱ゼロ — CTAクリックで紙吹雪をもう一度弾けさせる(お祝いの再生ボタン的な演出)
(() => {
  const cta = document.querySelector('[data-cta]');
  const pieces = document.querySelectorAll('.ead-piece');
  if (!cta || !pieces || pieces.length === 0) return; // null安全

  cta.addEventListener('click', () => {
    pieces.forEach((piece) => {
      piece.classList.remove('is-bursting');
      // 強制リフローで同じアニメーションを再始動できるようにする
      void piece.getBoundingClientRect();
      piece.classList.add('is-bursting');
    });
  });

  pieces.forEach((piece) => {
    piece.addEventListener('animationend', (e) => {
      if (e.animationName === 'ead-burst') piece.classList.remove('is-bursting');
    });
  });
})();

🤖 AIエージェント用プロンプト

このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「完了・受信箱ゼロ」の効果を追加してください。

# 追加してほしい効果
完了・受信箱ゼロ(アラート & 空状態)
チェックマークが描かれ、紙吹雪が漂う「すべて完了」の空状態。ボタンを押すたびに紙吹雪が弾け、達成感を演出します。受信箱ゼロの表示に最適です。

# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- 空状態: 完了・受信箱ゼロ。チェックが描画され、紙吹雪が漂う。CTAクリックで紙吹雪がもう一度弾ける -->
<main class="ead-card">
  <svg class="ead-illus" viewBox="0 0 200 170" width="168" height="143" role="img" aria-label="すべてのタスクが完了したことを示す、チェックマークと紙吹雪のイラスト">
    <g class="ead-confetti" data-confetti aria-hidden="true">
      <rect class="ead-piece ead-piece--1" x="28" y="38" width="10" height="10" rx="2"></rect>
      <circle class="ead-piece ead-piece--2" cx="170" cy="44" r="6"></circle>
      <rect class="ead-piece ead-piece--3" x="152" y="120" width="9" height="9" rx="2"></rect>
      <circle class="ead-piece ead-piece--4" cx="32" cy="122" r="5"></circle>
      <rect class="ead-piece ead-piece--5" x="96" y="16" width="8" height="8" rx="2"></rect>
      <circle class="ead-piece ead-piece--6" cx="158" cy="86" r="4.5"></circle>
    </g>
    <g class="ead-badge-group">
      <circle class="ead-badge-ring" cx="100" cy="82" r="40"></circle>
      <path class="ead-check" d="M82 82 L94 94 L120 66"></path>
    </g>
  </svg>

  <h2 class="ead-title">すべて完了しました!</h2>
  <p class="ead-desc">新しい通知はありません。今のうちに、少し休憩してくださいね。</p>

  <button class="ead-cta" type="button" data-cta>受信箱に戻る</button>
</main>

【CSS】
/* 空状態: 完了・受信箱ゼロ */
* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 32px 20px;
  font-family: "Hiragino Sans", "Yu Gothic UI", "Segoe UI", system-ui, -apple-system, sans-serif;
  background:
    radial-gradient(circle at 18% 16%, rgba(52, 211, 153, .16) 0%, transparent 46%),
    radial-gradient(circle at 86% 84%, rgba(253, 224, 71, .2) 0%, transparent 50%),
    #f7fdf9;
  color: #065f46;
}

.ead-card {
  width: 100%;
  max-width: 380px;
  background: #ffffff;
  border-radius: 24px;
  padding: 40px 32px 34px;
  text-align: center;
  box-shadow: 0 24px 60px -24px rgba(5, 150, 105, .24), 0 2px 8px rgba(6, 95, 70, .06);
  border: 1px solid rgba(52, 211, 153, .14);
}

.ead-illus { display: block; margin: 0 auto 8px; overflow: visible; }

.ead-badge-group {
  transform-box: fill-box;
  transform-origin: center;
  animation: ead-breathe 3s ease-in-out infinite;
}
@keyframes ead-breathe {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.04); }
}
.ead-badge-ring { fill: #d1fae5; stroke: #10b981; stroke-width: 4; }
.ead-check {
  fill: none;
  stroke: #047857;
  stroke-width: 8;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 56;
  stroke-dashoffset: 56;
  animation: ead-draw .6s .15s cubic-bezier(.22,1,.36,1) forwards;
}
@keyframes ead-draw { to { stroke-dashoffset: 0; } }

/* 漂う紙吹雪(アイドル) */
.ead-piece {
  transform-box: fill-box;
  transform-origin: center;
  animation: ead-float 3.6s ease-in-out infinite;
}
.ead-piece--1 { fill: #fbbf24; animation-delay: 0s; }
.ead-piece--2 { fill: #60a5fa; animation-delay: .5s; }
.ead-piece--3 { fill: #f472b6; animation-delay: 1s; }
.ead-piece--4 { fill: #a78bfa; animation-delay: 1.4s; }
.ead-piece--5 { fill: #34d399; animation-delay: .8s; }
.ead-piece--6 { fill: #fb923c; animation-delay: 1.8s; }
@keyframes ead-float {
  0%, 100% { transform: translateY(0) rotate(0deg); opacity: .55; }
  50% { transform: translateY(-8px) rotate(50deg); opacity: 1; }
}

/* クリックで再生する紙吹雪バースト */
.ead-piece.is-bursting { animation: ead-burst .7s cubic-bezier(.22,1,.36,1); }
@keyframes ead-burst {
  0% { transform: translate(0, 0) scale(1) rotate(0deg); opacity: 1; }
  70% { opacity: 1; }
  100% { transform: translate(var(--bx, 10px), var(--by, -18px)) scale(.6) rotate(160deg); opacity: 0; }
}
.ead-piece--1.is-bursting { --bx: -18px; --by: -16px; }
.ead-piece--2.is-bursting { --bx: 20px; --by: -14px; }
.ead-piece--3.is-bursting { --bx: 16px; --by: 18px; }
.ead-piece--4.is-bursting { --bx: -20px; --by: 16px; }
.ead-piece--5.is-bursting { --bx: 6px; --by: -22px; }
.ead-piece--6.is-bursting { --bx: 18px; --by: -6px; }

.ead-title { margin: 6px 0 10px; font-size: 21px; font-weight: 700; color: #065f46; }
.ead-desc { margin: 0 0 24px; font-size: 14.5px; line-height: 1.7; color: #4d7c6f; }

.ead-cta {
  appearance: none;
  border: none;
  cursor: pointer;
  padding: 13px 30px;
  font-size: 15px;
  font-weight: 600;
  color: #fff;
  background: linear-gradient(135deg, #34d399 0%, #059669 100%);
  border-radius: 999px;
  box-shadow: 0 12px 26px -10px rgba(5, 150, 105, .5);
  transition: transform .25s cubic-bezier(.22,1,.36,1), box-shadow .25s ease;
}
.ead-cta:hover { transform: translateY(-2px); box-shadow: 0 16px 32px -10px rgba(5, 150, 105, .6); }
.ead-cta:active { transform: translateY(0); }

@media (prefers-reduced-motion: reduce) {
  .ead-badge-group, .ead-piece { animation: none !important; }
  .ead-check { stroke-dashoffset: 0; animation: none !important; }
}

【JavaScript】
// 空状態: 完了・受信箱ゼロ — CTAクリックで紙吹雪をもう一度弾けさせる(お祝いの再生ボタン的な演出)
(() => {
  const cta = document.querySelector('[data-cta]');
  const pieces = document.querySelectorAll('.ead-piece');
  if (!cta || !pieces || pieces.length === 0) return; // null安全

  cta.addEventListener('click', () => {
    pieces.forEach((piece) => {
      piece.classList.remove('is-bursting');
      // 強制リフローで同じアニメーションを再始動できるようにする
      void piece.getBoundingClientRect();
      piece.classList.add('is-bursting');
    });
  });

  pieces.forEach((piece) => {
    piece.addEventListener('animationend', (e) => {
      if (e.animationName === 'ead-burst') piece.classList.remove('is-bursting');
    });
  });
})();

# 外部ライブラリ
なし(追加ライブラリ不要)

# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。