HTML/CSS
投稿日:

CTAは読み終わりで光る ─ 記事の最後に光るアニメーション

こんにちは、WebディレクターのBigViです。今回も私が対応したブログサイト制作プロジェクトの例を書いています。

私が対応したプロジェクトでは、多くのユーザーが記事を読んでいるけど、そこからお問合せページリンクしていないことが問題でした。お問い合わせページへのリンクはちゃんとありました。そこで私は、「記事の最後が見えたときに少しアニメーションをする」仕掛けを考えてみました。今回は、CTA(Call to Action)を読み終わりで光らせる小さなトリガーアニメーションの実装について紹介します。

目立たないお問合せボタン

普通のお問合せボタン(CTAボタン)は、記事の下に置かれていても見落とすことが多いです。特に、静的な要素だと記事に集中しているので見えていません。でも、読み終わる時に少し光る、または動くアニメーションが入ると、みんな必ずみます。強制的ではないけど、「あ、次はこれを押すかな」と思わせるんです。

実装の基本アイデア

この仕掛けは、JavaScriptのIntersectionObserverを使って、ユーザーが記事の最後に到達した瞬間をチェックします。そこからCSSアニメーションをスタートして、CTAボタンに「光る」ような効果を与えます。

<section class="article">
  <h1>記事タイトル</h1>
  <p>
    ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。<br>
    ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。<br>
.....
    ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。ダミーテキスト。<br>
  </p>

  <!-- 読了検知の“番兵”。CTAの直前に置く -->
  <div class="read-end-sentinel" aria-hidden="true"></div>

  <a id="cta" class="cta" href="javascript:void(0)">お問い合わせはこちら</a>
</section>

:root{
  /* ▼ここで“何回チカチカ”&“速さ”を調整 */
  --blink-iterations: 3;   /* 2 か 3 を推奨(=2回 or 3回の明滅) */
  --blink-duration: 0.22s; /* 1サイクルの長さ。0.16〜0.28s くらいが“チカチカ感”強め */
}

*{box-sizing:border-box}
body{
  font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Noto Sans JP",sans-serif;
  line-height:1.8; margin:0; padding:32px 16px 80px; background:#f7f7f9; color:#222;
}
.article{
  max-width:780px; margin:0 auto; background:#fff; padding:32px 28px 40px;
  border-radius:12px; box-shadow:0 6px 22px rgba(0,0,0,.06);
}
.read-end-sentinel{ height:1px; }

.cta{
  display:block; margin-top:24px; text-align:center; text-decoration:none;
  background:#0078d7; color:#fff; padding:16px 24px; border-radius:10px;
  box-shadow:none; opacity:1; transform:translateZ(0);
  transition: box-shadow .12s linear, opacity .12s linear, transform .12s linear;
}

/* ▼CSSアニメ“だけ”で明滅する。JSはこのクラスを付けるだけ */
.cta.is-blink{
  animation: ctaBlink var(--blink-duration) linear var(--blink-iterations);
}

/* 点滅後の“残光”(任意。不要なら削除OK) */
.cta.after-glow{
  box-shadow:0 0 20px 7px rgba(0,120,215,.80);
}

/* 明滅のON/OFFをはっきりさせるキーフレーム */
@keyframes ctaBlink{
  0%,100%{
    opacity:1;
    transform:scale(1.01);
    box-shadow:0 0 18px 6px rgba(0,120,215,.95);
  }
  50%{
    opacity:.18;
    transform:scale(1);
    box-shadow:none;
  }
}

/* モーション弱め設定の環境でも1回は視認できるように */
@media (prefers-reduced-motion: reduce){
  .cta{ transition:none; }
  .cta.is-blink{ animation:none; }
  .cta.after-glow{ box-shadow:0 0 24px 8px rgba(0,120,215,.85); }
}

const sentinel = document.querySelector('.read-end-sentinel');
const cta = document.getElementById('cta');

let wasIntersecting = false;

// アニメ再生を毎回“確実に”やり直すためのトリガー関数
function triggerBlink(){
  if(!cta) return;

  // 前回の状態をリセット(これで毎回CSSアニメを頭から再生できる)
  cta.classList.remove('is-blink','after-glow');

  // reflowでアニメを確実にリセット
  // (classの付け外しだけだとブラウザによっては再生されないことがあるため)
  // eslint-disable-next-line no-unused-expressions
  cta.offsetWidth;

  // CSSアニメーション開始(JSはクラスを付けるだけ)
  cta.classList.add('is-blink');

  // アニメ終了後に“残光”クラスを付与
  const computed = getComputedStyle(document.documentElement);
  const iters = parseInt(computed.getPropertyValue('--blink-iterations').trim() || '3', 10);
  const dur   = parseFloat((computed.getPropertyValue('--blink-duration').trim() || '0.22s').replace('s','')) * 1000;
  const total = iters * dur;

  // アニメーションイベントはCodePenの埋め込みで拾えないことがあるため、確実性重視でsetTimeout
  setTimeout(() => {
    cta.classList.remove('is-blink');
    cta.classList.add('after-glow');
  }, total + 30); // 少しバッファ
}

// 「非交差→交差」の瞬間だけ発火(上に戻って再び下ってきた時も毎回発火)
const io = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    const now = entry.isIntersecting;
    if(!wasIntersecting && now){
      triggerBlink();
    }
    wasIntersecting = now;
  });
}, {
  threshold: 0.05,
  rootMargin: '0px 0px -20% 0px' // 画面下から20%手前で発火
});

if(sentinel) io.observe(sentinel);

// 任意:CTAクリックで残光を消す(体験を締める)
cta?.addEventListener('click', () => {
  cta.classList.remove('after-glow','is-blink');
});

実際の案件での使い方

このスクリプトは実際の案件でも使用しました。長い記事で、最後のCTAがほとんどクリックされていなかったのですが、読み終わりのアニメーションを入れたことでCTR(クリック率)が約1.5倍に上がりました。アニメーションは一瞬だけ光るようにして、繰り返さない設定にしました。読者が自然に「次へ進もう」と感じる動きにすることが大切です。

まとめ

小さなアニメーションでも、読み終わりのアニメーションはクリック率をあげることができます。重要なのは「記事を邪魔しない自然なアニメーション」にすることです。

株式会社ファストコーディングでは、このようなUI改善の提案や実装も行っています。ぜひお気軽にご相談ください。

※本記事は弊社外国人スタッフによる投稿です。言い回しや表現が不十分な個所がありますことご容赦いただきますようお願いいたします。
株式会社ファストコーディング