下部シェア&いいねバー
記事下部に固定した、いいね・ブックマーク・コメント・シェアのアクションバー。数値カウンタ付きで反応を可視化します。クリックでハートが弾み、数が増える楽しい手応えを返します。
ライブデモ
使用例(お題: アイドルグループ Sakura)
この技法を「アイドルグループ Sakura」というテーマのダミーサイトで実際に使った例です。
HTML
<!-- Sakura:ファン記事の下部シェア&いいねバー -->
<div class="ssa-frame">
<div class="ssa-scroll" id="ssaScroll">
<article class="ssa-body">
<p class="ssa-cat">REPORT</p>
<h1>2ndツアー初日、現地レポート</h1>
<p>開演前から熱気に包まれた会場。読み進めると、下部にいいね・保存・シェアのバーが現れます。盛り上がりが数で伝わります。</p>
<p>新曲「星降る夜の桜物語」のパフォーマンスは圧巻。客席のペンライトが一面の桜色に。</p>
<p>このサンプルは自動で下までスクロールし、アクションバーの出現を実演します。いいねを押すとハートが弾みます。</p>
<p>最後まで読んでくれてありがとう。よかったら、下のハートを 🌸</p>
</article>
</div>
<div class="ssa-bar" id="ssaBar">
<button class="ssa-act" id="ssaLike" type="button" aria-pressed="false">
<span class="ssa-ico ssa-heart" aria-hidden="true">♥</span>
<span class="ssa-n" id="ssaLikeN">2,480</span>
</button>
<button class="ssa-act" type="button"><span class="ssa-ico" aria-hidden="true">🔖</span><span class="ssa-n">312</span></button>
<button class="ssa-act" type="button"><span class="ssa-ico" aria-hidden="true">💬</span><span class="ssa-n">96</span></button>
<button class="ssa-act ssa-act--share" type="button"><span class="ssa-ico" aria-hidden="true">↗</span>シェア</button>
</div>
</div>
CSS
/* Sakura(アイドル):下部シェア&いいねバーの再スキン */
* { box-sizing: border-box; }
body { margin: 0; font-family: "Segoe UI", system-ui, -apple-system, sans-serif; }
.ssa-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #fff5f9; }
.ssa-scroll { height: 100%; overflow-y: auto; scrollbar-width: thin; }
.ssa-body { padding: 26px 28px 96px; color: #4a2236; line-height: 1.85; max-width: 600px; }
.ssa-cat { margin: 0 0 8px; font-size: 11px; letter-spacing: .22em; font-weight: 700; color: #d6336c; }
.ssa-body h1 { margin: 0 0 14px; font-size: 24px; font-weight: 800; }
.ssa-body p { margin: 0 0 16px; font-size: 14px; color: #6a3e54; }
.ssa-bar { position: absolute; left: 50%; bottom: 18px; z-index: 10; transform: translate(-50%, 140%); display: flex; align-items: center; gap: 6px; padding: 8px; border-radius: 999px; background: #fff; border: 1px solid #ffd6e6; box-shadow: 0 14px 36px rgba(120,30,70,.16); opacity: 0; transition: transform .4s cubic-bezier(.2,.8,.2,1), opacity .3s ease; }
.ssa-bar.is-shown { transform: translate(-50%, 0); opacity: 1; }
.ssa-act { display: inline-flex; align-items: center; gap: 6px; font: inherit; font-size: 13px; font-weight: 700; color: #6a3e54; background: none; border: none; cursor: pointer; padding: 8px 13px; border-radius: 999px; transition: background .18s ease, color .18s ease; }
.ssa-act:hover { background: #fff0f5; }
.ssa-ico { font-size: 16px; line-height: 1; }
.ssa-heart { color: #e3b8c8; transition: transform .25s cubic-bezier(.3,1.5,.5,1), color .2s ease; }
.ssa-act.is-liked { color: #e11d48; }
.ssa-act.is-liked .ssa-heart { color: #e11d48; }
.ssa-act.is-pop .ssa-heart { transform: scale(1.4); }
.ssa-act--share { color: #fff; background: linear-gradient(135deg, #f06595, #d6336c); }
.ssa-act--share:hover { filter: brightness(1.05); }
@media (prefers-reduced-motion: reduce) { .ssa-bar, .ssa-heart { transition: none; } }
JavaScript
// (デモと同じフックを流用)スクロールでバー出現+いいね(弾み&カウント)+自動スクロール
(() => {
const sc = document.getElementById('ssaScroll');
const bar = document.getElementById('ssaBar');
const like = document.getElementById('ssaLike');
const likeN = document.getElementById('ssaLikeN');
if (!sc || !bar) return;
const apply = () => bar.classList.toggle('is-shown', sc.scrollTop > 70);
let ticking = false;
sc.addEventListener('scroll', () => { if (ticking) return; ticking = true; requestAnimationFrame(() => { apply(); ticking = false; }); }, { passive: true });
if (like && likeN) {
let n = 2480, liked = false;
like.addEventListener('click', () => {
liked = !liked; n += liked ? 1 : -1;
likeN.textContent = n.toLocaleString('en-US');
like.classList.toggle('is-liked', liked);
like.setAttribute('aria-pressed', liked ? 'true' : 'false');
like.classList.add('is-pop'); setTimeout(() => like.classList.remove('is-pop'), 260);
});
}
let auto = !matchMedia('(prefers-reduced-motion: reduce)').matches, dir = 1;
['wheel', 'touchstart', 'pointerdown'].forEach(ev => sc.addEventListener(ev, () => { auto = false; }, { passive: true }));
if (auto) {
setTimeout(function step() {
if (!auto) return;
const max = sc.scrollHeight - sc.clientHeight;
sc.scrollTop += dir * 1.6;
if (sc.scrollTop >= Math.min(max, 200)) dir = -1; else if (sc.scrollTop <= 0) dir = 1;
requestAnimationFrame(step);
}, 1100);
}
})();
実装ガイド
使いどころ
記事やファンコンテンツの下部に。いいね・保存・コメント・シェアのアクションバーで、反応を可視化してエンゲージメントを促します。
実装時の注意点
スクロールで中央下に出現。いいねはトグルでハートが弾み(scale)、色が変わり、数が増減します。数値は桁区切り表示。プレビューでは自動スクロールで出現を実演します。
対応ブラウザ
transform/opacity トランジション・Scroll イベントは全モダンブラウザ対応。
よくある失敗
数値は実データと同期し、二重カウントを防ぐこと(楽観的更新+サーバ確定)。固定バーが本文や他UIと重ならない位置に。シェアは各SNSの共有APIやWeb Share APIに接続します。
応用例
Web Share API 連携、いいね時のパーティクル演出、コメント投稿モーダル、保存済み一覧との連動などに展開できます。
コード
HTML
<!-- 記事下部のシェア&いいねアクションバー -->
<div class="ssa-frame">
<div class="ssa-scroll" id="ssaScroll">
<article class="ssa-body">
<p class="ssa-cat">JOURNAL</p>
<h1>小さな習慣が、一年を変える</h1>
<p>毎朝のたった5分。読み進めると、下部にいいね・保存・シェアのバーが現れます。反応を可視化することで、記事の盛り上がりが伝わります。</p>
<p>続けるコツは「やめないこと」より「再開しやすくすること」。仕組みで自分を助けましょう。</p>
<p>このデモは自動で下までスクロールし、アクションバーの出現を実演します。いいねを押すとハートが弾みます。</p>
<p>最後まで読んでくれてありがとう。よかったら、下のハートを。</p>
</article>
</div>
<div class="ssa-bar" id="ssaBar">
<button class="ssa-act" id="ssaLike" type="button" aria-pressed="false">
<span class="ssa-ico ssa-heart" aria-hidden="true">♥</span>
<span class="ssa-n" id="ssaLikeN">128</span>
</button>
<button class="ssa-act" type="button"><span class="ssa-ico" aria-hidden="true">🔖</span><span class="ssa-n">34</span></button>
<button class="ssa-act" type="button"><span class="ssa-ico" aria-hidden="true">💬</span><span class="ssa-n">12</span></button>
<button class="ssa-act ssa-act--share" type="button"><span class="ssa-ico" aria-hidden="true">↗</span>シェア</button>
</div>
</div>
CSS
* { box-sizing: border-box; }
body { margin: 0; font-family: "Segoe UI", system-ui, -apple-system, sans-serif; }
.ssa-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #fbfbfd; }
.ssa-scroll { height: 100%; overflow-y: auto; scrollbar-width: thin; }
.ssa-body { padding: 26px 28px 96px; color: #2a2e38; line-height: 1.85; max-width: 600px; }
.ssa-cat { margin: 0 0 8px; font-size: 11px; letter-spacing: .22em; font-weight: 700; color: #db2777; }
.ssa-body h1 { margin: 0 0 14px; font-size: 24px; font-weight: 800; }
.ssa-body p { margin: 0 0 16px; font-size: 14px; color: #4b4e5b; }
.ssa-bar {
position: absolute; left: 50%; bottom: 18px; z-index: 10; transform: translate(-50%, 140%);
display: flex; align-items: center; gap: 6px;
padding: 8px; border-radius: 999px;
background: #fff; border: 1px solid #e8ebf3; box-shadow: 0 14px 36px rgba(20,24,50,.16);
opacity: 0; transition: transform .4s cubic-bezier(.2,.8,.2,1), opacity .3s ease;
}
.ssa-bar.is-shown { transform: translate(-50%, 0); opacity: 1; }
.ssa-act { display: inline-flex; align-items: center; gap: 6px; font: inherit; font-size: 13px; font-weight: 700; color: #4a4f63; background: none; border: none; cursor: pointer; padding: 8px 13px; border-radius: 999px; transition: background .18s ease, color .18s ease; }
.ssa-act:hover { background: #f1f3f9; }
.ssa-ico { font-size: 16px; line-height: 1; }
.ssa-heart { color: #c8ccd8; transition: transform .25s cubic-bezier(.3,1.5,.5,1), color .2s ease; }
.ssa-act.is-liked { color: #e11d48; }
.ssa-act.is-liked .ssa-heart { color: #e11d48; }
.ssa-act.is-pop .ssa-heart { transform: scale(1.4); }
.ssa-act--share { color: #fff; background: #4f46e5; }
.ssa-act--share:hover { background: #4338ca; }
@media (prefers-reduced-motion: reduce) { .ssa-bar, .ssa-heart { transition: none; } }
JavaScript
// スクロールでバー出現+いいね(ハート弾み&カウント増減)。自動スクロールで実演
(() => {
const sc = document.getElementById('ssaScroll');
const bar = document.getElementById('ssaBar');
const like = document.getElementById('ssaLike');
const likeN = document.getElementById('ssaLikeN');
if (!sc || !bar) return;
const apply = () => bar.classList.toggle('is-shown', sc.scrollTop > 70);
let ticking = false;
sc.addEventListener('scroll', () => { if (ticking) return; ticking = true; requestAnimationFrame(() => { apply(); ticking = false; }); }, { passive: true });
if (like && likeN) {
let n = 128, liked = false;
like.addEventListener('click', () => {
liked = !liked;
n += liked ? 1 : -1;
likeN.textContent = n;
like.classList.toggle('is-liked', liked);
like.setAttribute('aria-pressed', liked ? 'true' : 'false');
like.classList.add('is-pop');
setTimeout(() => like.classList.remove('is-pop'), 260);
});
}
let auto = !matchMedia('(prefers-reduced-motion: reduce)').matches, dir = 1;
['wheel', 'touchstart', 'pointerdown'].forEach(ev => sc.addEventListener(ev, () => { auto = false; }, { passive: true }));
if (auto) {
setTimeout(function step() {
if (!auto) return;
const max = sc.scrollHeight - sc.clientHeight;
sc.scrollTop += dir * 1.6;
if (sc.scrollTop >= Math.min(max, 200)) dir = -1; else if (sc.scrollTop <= 0) dir = 1;
requestAnimationFrame(step);
}, 1100);
}
})();
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「下部シェア&いいねバー」の効果を追加してください。
# 追加してほしい効果
下部シェア&いいねバー(追従ウィジェット)
記事下部に固定した、いいね・ブックマーク・コメント・シェアのアクションバー。数値カウンタ付きで反応を可視化します。クリックでハートが弾み、数が増える楽しい手応えを返します。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- 記事下部のシェア&いいねアクションバー -->
<div class="ssa-frame">
<div class="ssa-scroll" id="ssaScroll">
<article class="ssa-body">
<p class="ssa-cat">JOURNAL</p>
<h1>小さな習慣が、一年を変える</h1>
<p>毎朝のたった5分。読み進めると、下部にいいね・保存・シェアのバーが現れます。反応を可視化することで、記事の盛り上がりが伝わります。</p>
<p>続けるコツは「やめないこと」より「再開しやすくすること」。仕組みで自分を助けましょう。</p>
<p>このデモは自動で下までスクロールし、アクションバーの出現を実演します。いいねを押すとハートが弾みます。</p>
<p>最後まで読んでくれてありがとう。よかったら、下のハートを。</p>
</article>
</div>
<div class="ssa-bar" id="ssaBar">
<button class="ssa-act" id="ssaLike" type="button" aria-pressed="false">
<span class="ssa-ico ssa-heart" aria-hidden="true">♥</span>
<span class="ssa-n" id="ssaLikeN">128</span>
</button>
<button class="ssa-act" type="button"><span class="ssa-ico" aria-hidden="true">🔖</span><span class="ssa-n">34</span></button>
<button class="ssa-act" type="button"><span class="ssa-ico" aria-hidden="true">💬</span><span class="ssa-n">12</span></button>
<button class="ssa-act ssa-act--share" type="button"><span class="ssa-ico" aria-hidden="true">↗</span>シェア</button>
</div>
</div>
【CSS】
* { box-sizing: border-box; }
body { margin: 0; font-family: "Segoe UI", system-ui, -apple-system, sans-serif; }
.ssa-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #fbfbfd; }
.ssa-scroll { height: 100%; overflow-y: auto; scrollbar-width: thin; }
.ssa-body { padding: 26px 28px 96px; color: #2a2e38; line-height: 1.85; max-width: 600px; }
.ssa-cat { margin: 0 0 8px; font-size: 11px; letter-spacing: .22em; font-weight: 700; color: #db2777; }
.ssa-body h1 { margin: 0 0 14px; font-size: 24px; font-weight: 800; }
.ssa-body p { margin: 0 0 16px; font-size: 14px; color: #4b4e5b; }
.ssa-bar {
position: absolute; left: 50%; bottom: 18px; z-index: 10; transform: translate(-50%, 140%);
display: flex; align-items: center; gap: 6px;
padding: 8px; border-radius: 999px;
background: #fff; border: 1px solid #e8ebf3; box-shadow: 0 14px 36px rgba(20,24,50,.16);
opacity: 0; transition: transform .4s cubic-bezier(.2,.8,.2,1), opacity .3s ease;
}
.ssa-bar.is-shown { transform: translate(-50%, 0); opacity: 1; }
.ssa-act { display: inline-flex; align-items: center; gap: 6px; font: inherit; font-size: 13px; font-weight: 700; color: #4a4f63; background: none; border: none; cursor: pointer; padding: 8px 13px; border-radius: 999px; transition: background .18s ease, color .18s ease; }
.ssa-act:hover { background: #f1f3f9; }
.ssa-ico { font-size: 16px; line-height: 1; }
.ssa-heart { color: #c8ccd8; transition: transform .25s cubic-bezier(.3,1.5,.5,1), color .2s ease; }
.ssa-act.is-liked { color: #e11d48; }
.ssa-act.is-liked .ssa-heart { color: #e11d48; }
.ssa-act.is-pop .ssa-heart { transform: scale(1.4); }
.ssa-act--share { color: #fff; background: #4f46e5; }
.ssa-act--share:hover { background: #4338ca; }
@media (prefers-reduced-motion: reduce) { .ssa-bar, .ssa-heart { transition: none; } }
【JavaScript】
// スクロールでバー出現+いいね(ハート弾み&カウント増減)。自動スクロールで実演
(() => {
const sc = document.getElementById('ssaScroll');
const bar = document.getElementById('ssaBar');
const like = document.getElementById('ssaLike');
const likeN = document.getElementById('ssaLikeN');
if (!sc || !bar) return;
const apply = () => bar.classList.toggle('is-shown', sc.scrollTop > 70);
let ticking = false;
sc.addEventListener('scroll', () => { if (ticking) return; ticking = true; requestAnimationFrame(() => { apply(); ticking = false; }); }, { passive: true });
if (like && likeN) {
let n = 128, liked = false;
like.addEventListener('click', () => {
liked = !liked;
n += liked ? 1 : -1;
likeN.textContent = n;
like.classList.toggle('is-liked', liked);
like.setAttribute('aria-pressed', liked ? 'true' : 'false');
like.classList.add('is-pop');
setTimeout(() => like.classList.remove('is-pop'), 260);
});
}
let auto = !matchMedia('(prefers-reduced-motion: reduce)').matches, dir = 1;
['wheel', 'touchstart', 'pointerdown'].forEach(ev => sc.addEventListener(ev, () => { auto = false; }, { passive: true }));
if (auto) {
setTimeout(function step() {
if (!auto) return;
const max = sc.scrollHeight - sc.clientHeight;
sc.scrollTop += dir * 1.6;
if (sc.scrollTop >= Math.min(max, 200)) dir = -1; else if (sc.scrollTop <= 0) dir = 1;
requestAnimationFrame(step);
}, 1100);
}
})();
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。