出現する下端CTAバー

少しスクロールすると画面下からスッと現れる追従CTAバー。価格や訴求と申し込みボタンを常に手の届く位置に置けます。ECやサービス、予約導線で離脱を防ぐ常套手段。閉じることも可能です。

#sticky#cta#conversion#scroll

ライブデモ

使用例(お題: アイドルグループ Sakura)

この技法を「アイドルグループ Sakura」というテーマのダミーサイトで実際に使った例です。

HTML
<!-- Sakura:ライブ特設ページの追従チケットバー -->
<div class="scb-frame">
  <div class="scb-scroll" id="scbScroll">
    <article class="scb-body">
      <h1>2nd LIVE TOUR「星降る夜の桜物語」</h1>
      <p>全国6都市をめぐるツアーが開幕。各公演の見どころと、先行抽選のスケジュールをご案内します。</p>
      <p>少し読み進めると、下からチケット申込バーがスッと現れます。常に視界の端に置くことで、申込のタイミングを逃しません。</p>
      <p>このサンプルは自動で下までスクロールし、バーの出現を見せます。閉じるボタンで非表示にもできます。</p>
      <p>東京公演はアリーナ、地方公演はホール。座席はすべて指定席です。</p>
      <p>最後までご覧いただきありがとうございます。会場でお会いしましょう。</p>
    </article>
  </div>

  <div class="scb-bar" id="scbBar">
    <div class="scb-bar__info">
      <span class="scb-bar__price"><b>先行抽選</b> 受付中</span>
      <span class="scb-bar__note">6/20 23:59 まで</span>
    </div>
    <button class="scb-bar__cta" type="button">チケットを申し込む</button>
    <button class="scb-bar__close" id="scbClose" type="button" aria-label="閉じる">✕</button>
  </div>
</div>
CSS
/* Sakura(アイドル):出現する下端CTAバーの再スキン */
* { box-sizing: border-box; }
body { margin: 0; font-family: "Hiragino Kaku Gothic ProN", "Segoe UI", system-ui, sans-serif; }

.scb-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #fff5f9; }

.scb-scroll { height: 100%; overflow-y: auto; scrollbar-width: thin; }
.scb-body { padding: 26px 28px 110px; color: #4a2236; line-height: 1.85; max-width: 600px; }
.scb-body h1 { font-size: 23px; font-weight: 800; margin: 0 0 14px; }
.scb-body p { margin: 0 0 16px; font-size: 14px; color: #6a3e54; }

.scb-bar {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 10;
  display: flex; align-items: center; gap: 16px; padding: 14px 20px;
  background: #fff; border-top: 1px solid #ffd6e6; box-shadow: 0 -8px 26px rgba(214,51,108,.12);
  transform: translateY(120%); transition: transform .4s cubic-bezier(.2,.8,.2,1);
}
.scb-bar.is-shown { transform: translateY(0); }
.scb-bar__info { display: flex; flex-direction: column; line-height: 1.3; }
.scb-bar__price { font-size: 13px; color: #9a6b80; }
.scb-bar__price b { font-size: 18px; font-weight: 800; color: #d6336c; }
.scb-bar__note { font-size: 11.5px; color: #a87b90; }
.scb-bar__cta { font: inherit; font-size: 14px; font-weight: 700; cursor: pointer; margin-left: auto; padding: 12px 24px; border-radius: 999px; border: none; color: #fff; background: linear-gradient(135deg, #f06595, #d6336c); transition: transform .15s ease, filter .15s ease; }
.scb-bar__cta:hover { filter: brightness(1.07); transform: translateY(-2px); }
.scb-bar__close { background: none; border: none; cursor: pointer; color: #b58aa0; font-size: 13px; padding: 6px; }
.scb-bar__close:hover { color: #6a3e54; }

@media (prefers-reduced-motion: reduce) { .scb-bar, .scb-bar__cta { transition: none; } }
JavaScript
// (デモと同じフックを流用)スクロール量で下端CTAバーを出現
(() => {
  const sc = document.getElementById('scbScroll');
  const bar = document.getElementById('scbBar');
  const close = document.getElementById('scbClose');
  if (!sc || !bar) return;
  let dismissed = false;
  const apply = () => { if (!dismissed) bar.classList.toggle('is-shown', sc.scrollTop > 60); };
  let ticking = false;
  sc.addEventListener('scroll', () => { if (ticking) return; ticking = true; requestAnimationFrame(() => { apply(); ticking = false; }); }, { passive: true });
  if (close) close.addEventListener('click', () => { dismissed = true; bar.classList.remove('is-shown'); });
  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);
  }
})();

実装ガイド

使いどころ

EC・サービス・予約・チケットなど、申込や購入へ確実に誘導したいページに。少しスクロールすると画面下からCTAバーがスッと現れ、行動導線を常に手の届く位置へ置きます。

実装時の注意点

しきい値を超えたら is-shown を付け、translateY(120%)→0 で下からせり上げます。閉じると dismissed フラグで再表示を抑止。本文を邪魔しないよう、出現は一定スクロール後に限定しています。

対応ブラウザ

transform アニメーション・Scroll イベントは全モダンブラウザで対応します。固定配置のため特別な対応は不要です。

よくある失敗

出現が早すぎると本文閲覧の邪魔になるので、ファーストビューを過ぎてから出すのが定石。閉じた状態を保存(localStorage)して再訪時に出さない配慮を。iOS Safari の下部ツールバーと重なるため、safe-area-inset を考慮した余白を取ります。

応用例

残数・締切の表示と連動、スクロール下方向でのみ表示、カート金額に応じた送料無料訴求、A/B での文言出し分けなどに展開できます。

コード

HTML
<!-- スクロールで下から出現する追従CTAバー -->
<div class="scb-frame">
  <div class="scb-scroll" id="scbScroll">
    <article class="scb-body">
      <h1>出現する下端CTAバー</h1>
      <p>少し読み進めると、画面下から申し込みバーがスッと現れます。常に視界の端に置くことで、行動のきっかけを逃しません。</p>
      <p>上端に固定するヘッダーCTAと違い、本文を邪魔しにくいのが利点。スクロール量がしきい値を超えたら表示します。</p>
      <p>このデモは自動で下までスクロールし、バーの出現を見せます。閉じるボタンで非表示にもできます。</p>
      <p>価格や残席、送料無料ラインなど「あと一歩」を後押しする情報を載せると効果的です。</p>
      <p>最後まで来ました。コンバージョン改善の定番テクニックです。</p>
    </article>
  </div>

  <div class="scb-bar" id="scbBar">
    <div class="scb-bar__info">
      <span class="scb-bar__price"><b>¥1,980</b> <s>¥2,800</s></span>
      <span class="scb-bar__note">本日中の申込で30%OFF</span>
    </div>
    <button class="scb-bar__cta" type="button">いますぐ申し込む</button>
    <button class="scb-bar__close" id="scbClose" type="button" aria-label="閉じる">✕</button>
  </div>
</div>
CSS
* { box-sizing: border-box; }
body { margin: 0; font-family: "Segoe UI", system-ui, -apple-system, sans-serif; }

.scb-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #f7f7fb; }

.scb-scroll { height: 100%; overflow-y: auto; scrollbar-width: thin; }
.scb-body { padding: 26px 28px 110px; color: #2b2d38; line-height: 1.85; max-width: 600px; }
.scb-body h1 { font-size: 24px; font-weight: 800; margin: 0 0 14px; }
.scb-body p { margin: 0 0 16px; font-size: 14px; color: #4b4e5b; }

.scb-bar {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 10;
  display: flex; align-items: center; gap: 16px;
  padding: 14px 20px;
  background: #fff; border-top: 1px solid #e9eaf1;
  box-shadow: 0 -8px 26px rgba(20,24,40,.1);
  transform: translateY(120%);
  transition: transform .4s cubic-bezier(.2,.8,.2,1);
}
.scb-bar.is-shown { transform: translateY(0); }

.scb-bar__info { display: flex; flex-direction: column; line-height: 1.3; }
.scb-bar__price { font-size: 13px; color: #9aa0b0; }
.scb-bar__price b { font-size: 22px; font-weight: 800; color: #db2777; }
.scb-bar__price s { margin-left: 4px; }
.scb-bar__note { font-size: 11.5px; color: #6b7180; }

.scb-bar__cta {
  font: inherit; font-size: 14px; font-weight: 700; cursor: pointer; margin-left: auto;
  padding: 12px 24px; border-radius: 999px; border: none; color: #fff;
  background: linear-gradient(135deg, #6366f1, #db2777);
  transition: transform .15s ease, filter .15s ease;
}
.scb-bar__cta:hover { filter: brightness(1.08); transform: translateY(-2px); }
.scb-bar__close { background: none; border: none; cursor: pointer; color: #9aa0b0; font-size: 13px; padding: 6px; }
.scb-bar__close:hover { color: #4b4e5b; }

@media (prefers-reduced-motion: reduce) { .scb-bar, .scb-bar__cta { transition: none; } }
JavaScript
// スクロール量がしきい値を超えたら下端CTAバーを出現させる
(() => {
  const sc = document.getElementById('scbScroll');
  const bar = document.getElementById('scbBar');
  const close = document.getElementById('scbClose');
  if (!sc || !bar) return;

  let dismissed = false;
  const apply = () => { if (!dismissed) bar.classList.toggle('is-shown', sc.scrollTop > 60); };
  let ticking = false;
  sc.addEventListener('scroll', () => {
    if (ticking) return; ticking = true;
    requestAnimationFrame(() => { apply(); ticking = false; });
  }, { passive: true });

  if (close) close.addEventListener('click', () => { dismissed = true; bar.classList.remove('is-shown'); });

  // 自動で下へスクロールして出現を実演
  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サイトに「出現する下端CTAバー」の効果を追加してください。

# 追加してほしい効果
出現する下端CTAバー(追従ウィジェット)
少しスクロールすると画面下からスッと現れる追従CTAバー。価格や訴求と申し込みボタンを常に手の届く位置に置けます。ECやサービス、予約導線で離脱を防ぐ常套手段。閉じることも可能です。

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

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- スクロールで下から出現する追従CTAバー -->
<div class="scb-frame">
  <div class="scb-scroll" id="scbScroll">
    <article class="scb-body">
      <h1>出現する下端CTAバー</h1>
      <p>少し読み進めると、画面下から申し込みバーがスッと現れます。常に視界の端に置くことで、行動のきっかけを逃しません。</p>
      <p>上端に固定するヘッダーCTAと違い、本文を邪魔しにくいのが利点。スクロール量がしきい値を超えたら表示します。</p>
      <p>このデモは自動で下までスクロールし、バーの出現を見せます。閉じるボタンで非表示にもできます。</p>
      <p>価格や残席、送料無料ラインなど「あと一歩」を後押しする情報を載せると効果的です。</p>
      <p>最後まで来ました。コンバージョン改善の定番テクニックです。</p>
    </article>
  </div>

  <div class="scb-bar" id="scbBar">
    <div class="scb-bar__info">
      <span class="scb-bar__price"><b>¥1,980</b> <s>¥2,800</s></span>
      <span class="scb-bar__note">本日中の申込で30%OFF</span>
    </div>
    <button class="scb-bar__cta" type="button">いますぐ申し込む</button>
    <button class="scb-bar__close" id="scbClose" type="button" aria-label="閉じる">✕</button>
  </div>
</div>

【CSS】
* { box-sizing: border-box; }
body { margin: 0; font-family: "Segoe UI", system-ui, -apple-system, sans-serif; }

.scb-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #f7f7fb; }

.scb-scroll { height: 100%; overflow-y: auto; scrollbar-width: thin; }
.scb-body { padding: 26px 28px 110px; color: #2b2d38; line-height: 1.85; max-width: 600px; }
.scb-body h1 { font-size: 24px; font-weight: 800; margin: 0 0 14px; }
.scb-body p { margin: 0 0 16px; font-size: 14px; color: #4b4e5b; }

.scb-bar {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 10;
  display: flex; align-items: center; gap: 16px;
  padding: 14px 20px;
  background: #fff; border-top: 1px solid #e9eaf1;
  box-shadow: 0 -8px 26px rgba(20,24,40,.1);
  transform: translateY(120%);
  transition: transform .4s cubic-bezier(.2,.8,.2,1);
}
.scb-bar.is-shown { transform: translateY(0); }

.scb-bar__info { display: flex; flex-direction: column; line-height: 1.3; }
.scb-bar__price { font-size: 13px; color: #9aa0b0; }
.scb-bar__price b { font-size: 22px; font-weight: 800; color: #db2777; }
.scb-bar__price s { margin-left: 4px; }
.scb-bar__note { font-size: 11.5px; color: #6b7180; }

.scb-bar__cta {
  font: inherit; font-size: 14px; font-weight: 700; cursor: pointer; margin-left: auto;
  padding: 12px 24px; border-radius: 999px; border: none; color: #fff;
  background: linear-gradient(135deg, #6366f1, #db2777);
  transition: transform .15s ease, filter .15s ease;
}
.scb-bar__cta:hover { filter: brightness(1.08); transform: translateY(-2px); }
.scb-bar__close { background: none; border: none; cursor: pointer; color: #9aa0b0; font-size: 13px; padding: 6px; }
.scb-bar__close:hover { color: #4b4e5b; }

@media (prefers-reduced-motion: reduce) { .scb-bar, .scb-bar__cta { transition: none; } }

【JavaScript】
// スクロール量がしきい値を超えたら下端CTAバーを出現させる
(() => {
  const sc = document.getElementById('scbScroll');
  const bar = document.getElementById('scbBar');
  const close = document.getElementById('scbClose');
  if (!sc || !bar) return;

  let dismissed = false;
  const apply = () => { if (!dismissed) bar.classList.toggle('is-shown', sc.scrollTop > 60); };
  let ticking = false;
  sc.addEventListener('scroll', () => {
    if (ticking) return; ticking = true;
    requestAnimationFrame(() => { apply(); ticking = false; });
  }, { passive: true });

  if (close) close.addEventListener('click', () => { dismissed = true; bar.classList.remove('is-shown'); });

  // 自動で下へスクロールして出現を実演
  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で提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。