いいねハートバースト
クリックでハートが弾み、放射状に色とりどりの粒子が飛び散る「いいね」ボタン。SNSやレビューのリアクションUIに使えます。
ライブデモ
使用例(お題: アイドルグループ Sakura)
この技法を「アイドルグループ Sakura」というテーマのダミーサイトで実際に使った例です。
HTML
<!-- Sakura: 楽曲MVページ。いいねハートバーストを主役に -->
<div class="sk">
<div class="mv">
<img class="mv__thumb" src="https://picsum.photos/480/270?random=53" alt="MVサムネイル">
<span class="mv__play" aria-hidden="true">▶</span>
<span class="mv__badge">NEW MV</span>
</div>
<div class="mv__bar">
<div class="mv__meta">
<h1 class="mv__title">春風セレナーデ - Music Video</h1>
<p class="mv__by">Sakura ・ 公開3日 ・ 12万回再生</p>
</div>
<button class="like" type="button" aria-pressed="false" aria-label="いいね">
<svg class="like__icon" viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 21s-7.5-4.7-9.7-9.3C1 8.4 2.6 5.5 5.6 5.1c1.9-.3 3.5.7 4.4 2.1.9-1.4 2.5-2.4 4.4-2.1 3 .4 4.6 3.3 3.3 6.6C19.5 16.3 12 21 12 21z"/>
</svg>
<span class="like__count">2480</span>
</button>
</div>
<p class="sk__hint">ハートを押して「いいね」してみてください</p>
</div>
CSS
/* Sakura アイドル テーマ: 桜ピンク/白/淡グレー */
* { box-sizing: border-box; }
body {
margin: 0;
font-family: "Hiragino Kaku Gothic ProN", "Segoe UI", system-ui, sans-serif;
background:
radial-gradient(circle at 50% -10%, #ffe3ee 0%, transparent 55%),
#fff7fb;
color: #6b4a58;
}
.sk {
height: 400px;
display: flex;
flex-direction: column;
justify-content: center;
gap: 10px;
padding: 0 28px;
}
/* MVサムネイル */
.mv {
position: relative;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 18px 40px rgba(232,90,146,.25);
aspect-ratio: 16 / 7;
}
.mv__thumb {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
filter: saturate(1.05);
}
.mv__play {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 56px;
height: 56px;
display: grid;
place-items: center;
font-size: 18px;
color: #e85a92;
background: rgba(255,255,255,.85);
border-radius: 50%;
box-shadow: 0 8px 20px rgba(0,0,0,.2);
padding-left: 3px;
}
.mv__badge {
position: absolute;
left: 12px;
top: 12px;
font-size: 11px;
font-weight: 800;
letter-spacing: .08em;
color: #fff;
background: #e85a92;
padding: 4px 11px;
border-radius: 999px;
}
/* タイトル+いいね行 */
.mv__bar {
display: flex;
align-items: center;
gap: 14px;
}
.mv__meta { flex: 1; min-width: 0; }
.mv__title {
margin: 0;
font-size: 16px;
font-weight: 800;
color: #4a3340;
}
.mv__by {
margin: 4px 0 0;
font-size: 12px;
color: #b08a9b;
}
/* 主役: いいねハートバースト */
.like {
position: relative;
display: inline-flex;
align-items: center;
gap: 8px;
flex: none;
font-size: 14px;
font-weight: 700;
color: #b08a9b;
background: #fff;
border: 1px solid #ffd6e6;
border-radius: 999px;
padding: 9px 18px;
cursor: pointer;
transition: color .2s ease, border-color .2s ease, transform .15s ease;
}
.like__icon {
width: 22px;
height: 22px;
fill: #e7b9c9;
transition: fill .2s ease, transform .25s cubic-bezier(.34,1.56,.64,1);
}
.like.is-active {
color: #e85a92;
border-color: #ff9ec2;
}
.like.is-active .like__icon {
fill: #ff4d8d;
transform: scale(1.18);
}
.like:active { transform: scale(.96); }
/* 放射状に飛ぶ粒子 */
.spark {
position: absolute;
left: 22px;
top: 50%;
width: 7px;
height: 7px;
border-radius: 50%;
pointer-events: none;
animation: spark-out .6s ease-out forwards;
}
@keyframes spark-out {
0% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
100% { transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(0); opacity: 0; }
}
.sk__hint {
margin: 2px 0 0;
font-size: 11px;
color: #c79bb0;
}
@media (prefers-reduced-motion: reduce) {
.like, .like__icon { transition: none; }
}
JavaScript
// SakuraのMVいいね: トグルで色変化+粒子を放射状に飛ばす
(() => {
const btn = document.querySelector('.like');
const count = document.querySelector('.like__count');
if (!btn || !count) return; // null安全
const base = parseInt(count.textContent, 10) || 0;
let liked = false;
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const COLORS = ['#ff4d8d', '#ff9ec2', '#ffd166', '#a6d8ff', '#c8a6ff'];
// 放射状に粒子を生成
const burst = () => {
if (reduce) return;
const N = 10;
for (let i = 0; i < N; i++) {
const s = document.createElement('span');
s.className = 'spark';
const angle = (Math.PI * 2 * i) / N + Math.random() * 0.4;
const dist = 24 + Math.random() * 20;
s.style.setProperty('--dx', `${Math.cos(angle) * dist}px`);
s.style.setProperty('--dy', `${Math.sin(angle) * dist}px`);
s.style.background = COLORS[i % COLORS.length];
s.addEventListener('animationend', () => s.remove());
btn.appendChild(s);
}
};
btn.addEventListener('click', () => {
liked = !liked;
btn.classList.toggle('is-active', liked);
btn.setAttribute('aria-pressed', String(liked));
// いいね数を即時反映(整形してカンマ区切り)
count.textContent = (base + (liked ? 1 : 0)).toLocaleString('ja-JP');
if (liked) burst(); // 「いいね」した瞬間だけ弾ける
});
})();
コード
HTML
<!-- いいねハートバースト: クリックで弾けて粒子が飛び散る -->
<div class="stage">
<button class="like" type="button" aria-pressed="false" aria-label="いいね">
<svg class="like__heart" viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 21s-7.5-4.6-10-9.2C.3 8.6 1.8 5 5.2 5c2 0 3.3 1.1 4 2.2C9.9 6.1 11.2 5 13.2 5c3.4 0 4.9 3.6 3.2 6.8C19.5 16.4 12 21 12 21z"/>
</svg>
<span class="like__count">128</span>
</button>
<p class="hint">クリックして「いいね」</p>
</div>
CSS
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
font-family: "Segoe UI", system-ui, sans-serif;
background: linear-gradient(135deg, #fff1f3 0%, #ffe3ec 100%);
}
.stage {
display: grid;
place-items: center;
gap: 18px;
}
/* いいねボタン */
.like {
position: relative;
display: inline-flex;
align-items: center;
gap: 12px;
padding: 14px 26px;
border: none;
border-radius: 999px;
cursor: pointer;
background: #fff;
box-shadow: 0 10px 26px rgba(255, 87, 124, .18);
transition: transform .12s ease, box-shadow .25s ease;
-webkit-tap-highlight-color: transparent;
}
.like:active { transform: scale(.95); }
.like__heart {
width: 30px;
height: 30px;
fill: #d7dbe3;
transition: fill .2s ease, transform .25s cubic-bezier(.68,-0.55,.27,1.55);
}
/* 押下時の弾むスケール(JSが付与) */
.like.is-active .like__heart {
fill: #ff4d6d;
animation: heart-pop .45s cubic-bezier(.34,1.56,.64,1);
}
@keyframes heart-pop {
0% { transform: scale(.2); }
45% { transform: scale(1.35); }
100% { transform: scale(1); }
}
.like__count {
font-size: 18px;
font-weight: 700;
color: #44424d;
font-variant-numeric: tabular-nums;
}
.like.is-active .like__count { color: #ff4d6d; }
/* 飛び散る粒子(JSで生成) */
.spark {
position: absolute;
top: 50%;
left: 27px; /* ハート中心付近 */
width: 8px;
height: 8px;
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
animation: spark-fly .6s ease-out forwards;
}
@keyframes spark-fly {
0% { opacity: 1; transform: translate(-50%, -50%) translate(0, 0) scale(1); }
100% { opacity: 0; transform: translate(-50%, -50%) translate(var(--dx), var(--dy)) scale(.2); }
}
.hint {
margin: 0;
font-size: 13px;
color: #9a879a;
}
@media (prefers-reduced-motion: reduce) {
.like.is-active .like__heart { animation: none; }
.spark { animation-duration: .01ms; }
}
JavaScript
// いいねハートバースト: トグルで色変化+粒子を放射状に飛ばす
(() => {
const btn = document.querySelector('.like');
const count = document.querySelector('.like__count');
if (!btn || !count) return; // null安全
const base = parseInt(count.textContent, 10) || 0;
let liked = false;
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const COLORS = ['#ff4d6d', '#ffa1b5', '#ffd166', '#8ac6ff', '#c08bff'];
// 放射状に粒子を生成
const burst = () => {
if (reduce) return;
const N = 10;
for (let i = 0; i < N; i++) {
const s = document.createElement('span');
s.className = 'spark';
const angle = (Math.PI * 2 * i) / N + Math.random() * 0.4;
const dist = 26 + Math.random() * 22;
s.style.setProperty('--dx', `${Math.cos(angle) * dist}px`);
s.style.setProperty('--dy', `${Math.sin(angle) * dist}px`);
s.style.background = COLORS[i % COLORS.length];
s.addEventListener('animationend', () => s.remove());
btn.appendChild(s);
}
};
btn.addEventListener('click', () => {
liked = !liked;
btn.classList.toggle('is-active', liked);
btn.setAttribute('aria-pressed', String(liked));
count.textContent = String(base + (liked ? 1 : 0));
if (liked) burst(); // 「いいね」した瞬間だけ弾ける
});
})();
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「いいねハートバースト」の効果を追加してください。
# 追加してほしい効果
いいねハートバースト(マイクロインタラクション)
クリックでハートが弾み、放射状に色とりどりの粒子が飛び散る「いいね」ボタン。SNSやレビューのリアクションUIに使えます。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- いいねハートバースト: クリックで弾けて粒子が飛び散る -->
<div class="stage">
<button class="like" type="button" aria-pressed="false" aria-label="いいね">
<svg class="like__heart" viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 21s-7.5-4.6-10-9.2C.3 8.6 1.8 5 5.2 5c2 0 3.3 1.1 4 2.2C9.9 6.1 11.2 5 13.2 5c3.4 0 4.9 3.6 3.2 6.8C19.5 16.4 12 21 12 21z"/>
</svg>
<span class="like__count">128</span>
</button>
<p class="hint">クリックして「いいね」</p>
</div>
【CSS】
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
font-family: "Segoe UI", system-ui, sans-serif;
background: linear-gradient(135deg, #fff1f3 0%, #ffe3ec 100%);
}
.stage {
display: grid;
place-items: center;
gap: 18px;
}
/* いいねボタン */
.like {
position: relative;
display: inline-flex;
align-items: center;
gap: 12px;
padding: 14px 26px;
border: none;
border-radius: 999px;
cursor: pointer;
background: #fff;
box-shadow: 0 10px 26px rgba(255, 87, 124, .18);
transition: transform .12s ease, box-shadow .25s ease;
-webkit-tap-highlight-color: transparent;
}
.like:active { transform: scale(.95); }
.like__heart {
width: 30px;
height: 30px;
fill: #d7dbe3;
transition: fill .2s ease, transform .25s cubic-bezier(.68,-0.55,.27,1.55);
}
/* 押下時の弾むスケール(JSが付与) */
.like.is-active .like__heart {
fill: #ff4d6d;
animation: heart-pop .45s cubic-bezier(.34,1.56,.64,1);
}
@keyframes heart-pop {
0% { transform: scale(.2); }
45% { transform: scale(1.35); }
100% { transform: scale(1); }
}
.like__count {
font-size: 18px;
font-weight: 700;
color: #44424d;
font-variant-numeric: tabular-nums;
}
.like.is-active .like__count { color: #ff4d6d; }
/* 飛び散る粒子(JSで生成) */
.spark {
position: absolute;
top: 50%;
left: 27px; /* ハート中心付近 */
width: 8px;
height: 8px;
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
animation: spark-fly .6s ease-out forwards;
}
@keyframes spark-fly {
0% { opacity: 1; transform: translate(-50%, -50%) translate(0, 0) scale(1); }
100% { opacity: 0; transform: translate(-50%, -50%) translate(var(--dx), var(--dy)) scale(.2); }
}
.hint {
margin: 0;
font-size: 13px;
color: #9a879a;
}
@media (prefers-reduced-motion: reduce) {
.like.is-active .like__heart { animation: none; }
.spark { animation-duration: .01ms; }
}
【JavaScript】
// いいねハートバースト: トグルで色変化+粒子を放射状に飛ばす
(() => {
const btn = document.querySelector('.like');
const count = document.querySelector('.like__count');
if (!btn || !count) return; // null安全
const base = parseInt(count.textContent, 10) || 0;
let liked = false;
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const COLORS = ['#ff4d6d', '#ffa1b5', '#ffd166', '#8ac6ff', '#c08bff'];
// 放射状に粒子を生成
const burst = () => {
if (reduce) return;
const N = 10;
for (let i = 0; i < N; i++) {
const s = document.createElement('span');
s.className = 'spark';
const angle = (Math.PI * 2 * i) / N + Math.random() * 0.4;
const dist = 26 + Math.random() * 22;
s.style.setProperty('--dx', `${Math.cos(angle) * dist}px`);
s.style.setProperty('--dy', `${Math.sin(angle) * dist}px`);
s.style.background = COLORS[i % COLORS.length];
s.addEventListener('animationend', () => s.remove());
btn.appendChild(s);
}
};
btn.addEventListener('click', () => {
liked = !liked;
btn.classList.toggle('is-active', liked);
btn.setAttribute('aria-pressed', String(liked));
count.textContent = String(base + (liked ? 1 : 0));
if (liked) burst(); // 「いいね」した瞬間だけ弾ける
});
})();
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。