UI/UX
投稿日:

“次にすべきこと”が現れる ─ 説明文読了で次のCTAを淡くスライドイン

次にすべきことが現れる ─ 説明文読了で次のCTAを淡くスライドイン

こんにちは、Webディレクターの BigViです。

先日、お客さまから「ボタンを目立たせたいけど、最初から見せると邪魔になる」という相談を受けました。ユーザーが説明を読み終わった時に、ちょうどいいタイミングでボタンを見せたいということでした。

確かに、最初からボタンがあると気になります。でも、読み終わった時にボタンがないと、次に何をすればいいかわからないです。私も同じ経験があります。

読了検知でCTAをスライドイン

この課題に対して、私はIntersectionObserverという方法を使いました。説明文の最後が画面に入った瞬間に、その下のボタンが下から8pxスライドして出てきます。180msのアニメーションで、ふわっと現れる感じです。

常時表示しないことで、読んでいる時は邪魔になりません。読み終わった時だけ、「次はこちら」というボタンが見えます。ちょうどいいタイミングで出てくるので、ユーザーも自然に押してくれました。

HTML構造

まず、HTMLはこういう構造にします。説明文をしっかり読んでもらって、最後の段落が画面に入った瞬間にCTAボックスが下からスライドインします。

<article class="product-intro">
  <h2>私たちのサービスについて</h2>
  
  <p>
    当社では、Web制作からデザイン、マーケティングまで
    一貫したサポートを提供しています。
  </p>
  
  <p>
    お客様のビジネスに合わせた最適な提案を行い、
    成果を出すための戦略を一緒に考えます。
  </p>
  
  <!-- ↓この段落が画面に入った瞬間、次のCTAボックスが下からスライドイン -->
  <p class="last-paragraph" data-cta-trigger>
    まずは無料相談で、あなたのビジネスについて
    お聞かせください。一緒に成長戦略を考えましょう。
  </p>
  
  <!-- ↓読了した瞬間に下から8pxスライドインして現れるCTAボックス -->
  <div class="context-cta" data-cta-box>
    <h3>次のステップ</h3>
    <p>今すぐ無料相談を予約しませんか?</p>
    <a href="/contact" class="cta-button">無料相談を予約する</a>
  </div>
</article>

data-cta-triggerという属性を最後の段落につけます。data-cta-boxはCTAボックスです。最後の段落が画面に入った瞬間に、その直後のCTAボックスが下から8pxスライドして現れます。

CSSスタイル

CSSで、最初はCTAボックスを隠します。そして、.showというクラスがついた時だけ、下からスライドして出てきます。

      /* CTAボックス - 初期状態は完全に非表示 */
      .context-cta {
        opacity: 0;
        transform: translateY(30px);
        transition: opacity 0.6s ease-out, transform 0.6s ease-out;

        margin-top: 2rem;
        padding: 2rem;
        background: #e3f2fd;
        border: 2px solid #2196f3;
        border-radius: 12px;
        text-align: center;
      }

      /* showクラスがついたら表示 */
      .context-cta.show {
        opacity: 1;
        transform: translateY(0);
      }

      .context-cta h3 {
        font-size: 1.5rem;
        margin-bottom: 1rem;
        color: #1976d2;
      }

      .context-cta p {
        margin-bottom: 1.5rem;
        color: #555;
      }

      .cta-button {
        display: inline-block;
        padding: 1rem 2.5rem;
        background: #2196f3;
        color: white;
        text-decoration: none;
        border-radius: 8px;
        font-weight: bold;
        font-size: 1.1rem;
        transition: background 0.3s, transform 0.2s;
      }

      .cta-button:hover {
        background: #1976d2;
        transform: translateY(-2px);
      }

最初はopacity: 0で見えないです。transform: translateY(8px)で、下に8px隠れています。showクラスがつくと、opacity: 1で見えて、translateY(0)で元の位置に戻ります。これが下から8pxスライドインする動きです。180msで動くので、ふわっとした感じです。

prefers-reduced-motionというのは、動きが苦手な人のための設定です。この設定がオンの人には、アニメーションをオフにします。大事なことです。

JavaScriptの実装

JavaScriptで、IntersectionObserverを使います。これは、要素が画面に入ったかどうかを監視するAPIです。最後の段落が画面に入った瞬間に、CTAボックスにshowクラスをつけて、下からスライドインさせます。

      // ページ読み込み完了後に実行
      window.addEventListener('load', function() {
        const trigger = document.querySelector('[data-cta-trigger]');
        const ctaBox = document.querySelector('[data-cta-box]');

        console.log('🎯 トリガー要素:', trigger);
        console.log('📦 CTAボックス:', ctaBox);

        if (!trigger || !ctaBox) {
          console.error('❌ 要素が見つかりません');
          return;
        }

        // IntersectionObserverを作成
        const observer = new IntersectionObserver(function(entries) {
          entries.forEach(function(entry) {
            console.log('👁️ 画面内表示率:', Math.round(entry.intersectionRatio * 100) + '%');

            // 50%以上表示されたら
            if (entry.isIntersecting) {
              console.log('✅ トリガー発火! showクラスを追加');
              ctaBox.classList.add('show');
              // 一度だけ実行
              observer.unobserve(trigger);
            }
          });
        }, {
          // 要素の50%が見えたら発火
          threshold: 0.5,
          rootMargin: '0px'
        });

        // 監視開始
        observer.observe(trigger);
        console.log('👀 監視開始');

        // 初期位置をチェック
        const rect = trigger.getBoundingClientRect();
        const isVisible = rect.top < window.innerHeight;
        console.log('📍 初期位置:', {
          top: rect.top,
          windowHeight: window.innerHeight,
          画面内: isVisible ? 'はい(すぐ発火します)' : 'いいえ(スクロールが必要)'
        });
      });

このコードは、最後の段落が画面に入った時に、CTAボックスにshowクラスをつけます。CSSで、showクラスがつくと下から8pxスライドインするように書いたので、これで動きます。

threshold: 0.5というのは、要素の50%が見えた時に発火するという意味です。最後の段落の半分が見えたら、CTAボックスが下からスライドインします。ちょうどいいタイミングです。

observer.unobserve(trigger)で、一度CTAボックスが出たら監視を止めます。何度も動かないようにするためです。

実際の動作イメージ

ユーザーがページをスクロールして、説明文を読んでいきます:

  1. 「当社では、Web制作から…」を読む → CTAボックスはまだ見えない
  2. 「お客様のビジネスに合わせた…」を読む → CTAボックスはまだ見えない
  3. 「まずは無料相談で…」の段落が画面に入る → この瞬間にCTAボックスが下からスライドイン!
  4. 「次のステップ」「今すぐ無料相談を予約しませんか?」が自然に現れる

説明を読み終わったちょうどそのタイミングで、次にすべきことが目の前に現れます。ユーザーは「あ、次はこれか」と自然に理解して、ボタンを押してくれます。

まとめ

今回のポイントは以下の3つです:

  • IntersectionObserverで読了検知: 最後の段落が画面に入った時にCTAを出す
  • 控えめなアニメーション: 8px/180msぐらいのスライドインで、邪魔にならない
  • prefers-reduced-motion対応: 動きが苦手な人のために、アニメーションをオフにできる

常時表示しないことで、読んでいる時は邪魔になりません。読み終わった時だけCTAボックスが下からスライドインするので、ユーザーも自然に押してくれます。CVR改善にも効果がありました。

株式会社ファストコーディングでは、こうした実装のサポートも行っています。ご興味がある方はお問い合わせフォームからご連絡ください。


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