Scroll Story UIの作り方|スクロール連動で内容が切り替わるUI

Scroll Story UIのアイキャッチ画像

スクロールに合わせて、左のビジュアルや説明が切り替わるUIを見かけることがあります。
プロダクト紹介、機能説明、サービスLPなどでよく使われる見せ方です。

このUIは、ただ派手なだけではありません。
「ユーザーのスクロール進行に合わせて、見せたい情報を順番に伝えられる」 という強みがあります。

この記事では、Scroll Story UI(実践編) として、
スクロール位置に応じてSTEPごとの内容を切り替えるレイアウトを、初心者にも追いやすい形で実装していきます。

今回は次のような流れで作ります。

  • 右側に複数のステップを縦に並べる
  • 左側には現在のステップに対応した表示を固定して見せる
  • スクロール位置に応じてアクティブな内容を切り替える
  • 最低限のJavaScriptで動く形にする

「Scroll Trigger Animationをもう少し実用寄りにしたい」
「Sticky Scroll Animationを、ストーリー型UIとして発展させたい」
という人にもつながる内容です。

1.Scroll Story UIとは?

Scroll Story UIは、スクロールを読み進める行為そのものを、情報の切り替え操作として使うUIです。

たとえば次のような場面で使われます。

  • サービスの特徴を順番に紹介したい
  • アプリの使い方をステップ形式で見せたい
  • 1画面の中で、文章とビジュアルを連動させたい
  • 長い説明を、単調にならない形で見せたい

特に、
右側に文章のステップ群
左側に固定されたビジュアルや要約表示
という構成はかなり定番です。

今回の実装でも、この形をベースに進めます。

2.今回作るUIの完成イメージ

今回の完成形は、次のような構成です。

  • セクション全体は左右2カラム
  • 左カラムは position: sticky で追従表示
  • 右カラムには複数のSTEPカードを並べる
  • スクロールして各STEPが見えてくると、左側の表示が切り替わる
  • アクティブなSTEPには見た目の強調を入れる

つまり、
右側を読むと、左側の表示が対応して切り替わる
という「読む動き」と「視覚の変化」がつながったUIです。

このあたりの基本となる考え方は、前回の
Sticky Scroll Animationの作り方
ともかなり近いです。
stickyで固定する仕組みがまだ曖昧なら、先にそちらを読むと理解しやすくなります。

また、要素が画面内に入ったことをきっかけに状態を切り替える発想は、
Scroll Trigger Animationの作り方
ともつながっています。

3.先に全体構成を確認する

まずはHTMLの全体像を見ておきます。

  • .story-shell … 全体ラッパー
  • .story-pin … 左側の固定表示
  • .story-steps … 右側のステップ一覧
  • .story-step … 各ステップ要素
  • data-step … 対応するステップ番号
  • 左側の表示も data-panel で切り替える

このように、
右側のSTEPと左側の表示を、番号で対応付ける
だけでもかなりシンプルに作れます。

複雑な状態管理を最初から入れなくても、
「今どのSTEPがアクティブか」
さえ取れれば十分です。

HTML

まずはマークアップです。

<section class="scroll-story">
  <div class="story-shell">
    <div class="story-pin">
      <div class="story-display">
        <p class="story-label">Scroll Story UI</p>
        <h2 class="story-title">STEP 1</h2>
        <p class="story-text">
          最初の導入メッセージです。スクロールに合わせて内容が切り替わります。
        </p>

        <div class="story-panels">
          <div class="story-panel is-active" data-panel="1">01</div>
          <div class="story-panel" data-panel="2">02</div>
          <div class="story-panel" data-panel="3">03</div>
          <div class="story-panel" data-panel="4">04</div>
        </div>
      </div>
    </div>

    <div class="story-steps">
      <article class="story-step is-active" data-step="1">
        <span class="step-kicker">STEP 1</span>
        <h3>導入で興味を引く</h3>
        <p>
          最初のステップでは、何について説明するUIなのかを短く伝えます。
          ここで読む理由が伝わると、次のステップにも進みやすくなります。
        </p>
      </article>

      <article class="story-step" data-step="2">
        <span class="step-kicker">STEP 2</span>
        <h3>特徴を整理して見せる</h3>
        <p>
          2つ目のステップでは、機能や特徴を分かりやすく提示します。
          テキストだけでなく、左側の表示を連動させることで理解しやすくなります。
        </p>
      </article>

      <article class="story-step" data-step="3">
        <span class="step-kicker">STEP 3</span>
        <h3>変化を視覚で補強する</h3>
        <p>
          スクロールに応じて表示が切り替わると、ユーザーは今どこを読んでいるかを把握しやすくなります。
          情報を段階的に見せたいときに有効です。
        </p>
      </article>

      <article class="story-step" data-step="4">
        <span class="step-kicker">STEP 4</span>
        <h3>最後に印象をまとめる</h3>
        <p>
          最終ステップでは、全体のまとめや行動導線を置くと相性が良いです。
          単なる説明で終わらず、次のアクションにつなげやすくなります。
        </p>
      </article>
    </div>
  </div>
</section>

CSS

次に見た目を整えます。
左側は sticky、右側は読み進めるための縦並びレイアウトです。

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: sans-serif;
  background: #0f1115;
  color: #f5f7fb;
}

.scroll-story {
  padding: 80px 20px;
}

.story-shell {
  max-width: 1100px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  align-items: start;
}

.story-pin {
  position: relative;
}

.story-display {
  position: sticky;
  top: 80px;
  min-height: 420px;
  padding: 32px;
  border-radius: 24px;
  background: linear-gradient(180deg, #181d27 0%, #12161d 100%);
  border: 1px solid rgba(255,255,255,0.08);
}

.story-label {
  margin: 0 0 12px;
  font-size: 14px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #8ea3ff;
}

.story-title {
  margin: 0 0 12px;
  font-size: 40px;
  line-height: 1.1;
}

.story-text {
  margin: 0;
  font-size: 16px;
  line-height: 1.8;
  color: rgba(255,255,255,0.8);
  max-width: 32ch;
}

.story-panels {
  display: flex;
  gap: 12px;
  margin-top: 28px;
}

.story-panel {
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  border-radius: 16px;
  font-weight: 700;
  background: rgba(255,255,255,0.06);
  color: rgba(255,255,255,0.5);
  transition: 0.3s ease;
}

.story-panel.is-active {
  background: #8ea3ff;
  color: #10131a;
  transform: translateY(-4px);
}

.story-steps {
  display: grid;
  gap: 24px;
}

.story-step {
  min-height: 72vh;
  padding: 28px;
  border-radius: 24px;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.08);
  opacity: 0.45;
  transform: scale(0.98);
  transition: opacity 0.3s ease, transform 0.3s ease, border-color 0.3s ease;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.story-step.is-active {
  opacity: 1;
  transform: scale(1);
  border-color: rgba(142,163,255,0.6);
}

.step-kicker {
  display: inline-block;
  margin-bottom: 12px;
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #8ea3ff;
}

.story-step h3 {
  margin: 0 0 12px;
  font-size: 30px;
  line-height: 1.3;
}

.story-step p {
  margin: 0;
  font-size: 16px;
  line-height: 1.9;
  color: rgba(255,255,255,0.8);
}

@media (max-width: 900px) {
  .story-shell {
    grid-template-columns: 1fr;
  }

  .story-display {
    position: static;
    min-height: auto;
  }

  .story-step {
    min-height: auto;
  }
}

4.ここまでのポイント

この段階で重要なのは、左側の固定表示をCSSだけで作っていることです。

JavaScriptはまだ使っていませんが、
position: sticky; top: 80px;
を入れるだけで、左側の表示がスクロール中に追従してくれます。

この「固定される見せ方」があるだけで、かなりそれっぽいUIになります。

逆にいうと、Scroll Story UIは
アニメーション技術が主役というより、レイアウト設計が主役
の場面も多いです。

スクロール系UIの見せ方を整理したい場合は、
Scroll Snap Animationの作り方
も合わせて読むと比較しやすいです。
snapは「区切って止める」方向、story UIは「読みながら切り替える」方向の違いがあります。

5.JavaScriptでアクティブなSTEPを切り替える

次に、スクロール位置に応じてアクティブなSTEPを切り替えます。

今回はシンプルに、各 .story-step の位置を見て
画面中央に最も近い要素をアクティブ扱い
にします。

<script>
  const steps = document.querySelectorAll('.story-step');
  const panels = document.querySelectorAll('.story-panel');
  const title = document.querySelector('.story-title');
  const text = document.querySelector('.story-text');

  const contentMap = {
    1: {
      title: 'STEP 1',
      text: '最初の導入メッセージです。スクロールに合わせて内容が切り替わります。'
    },
    2: {
      title: 'STEP 2',
      text: '特徴を整理して見せるステップです。左側の表示も連動して変化します。'
    },
    3: {
      title: 'STEP 3',
      text: '視覚の変化を加えることで、今どの話を読んでいるかが分かりやすくなります。'
    },
    4: {
      title: 'STEP 4',
      text: '最後のまとめや導線設計にも使いやすいのが、Scroll Story UIの良いところです。'
    }
  };

  function setActiveStep(stepNumber) {
    steps.forEach(step => {
      step.classList.toggle('is-active', step.dataset.step === String(stepNumber));
    });

    panels.forEach(panel => {
      panel.classList.toggle('is-active', panel.dataset.panel === String(stepNumber));
    });

    title.textContent = contentMap[stepNumber].title;
    text.textContent = contentMap[stepNumber].text;
  }

  function updateActiveStep() {
    let closestStep = null;
    let closestDistance = Infinity;

    steps.forEach(step => {
      const rect = step.getBoundingClientRect();
      const stepCenter = rect.top + rect.height / 2;
      const viewportCenter = window.innerHeight / 2;
      const distance = Math.abs(stepCenter - viewportCenter);

      if (distance < closestDistance) {
        closestDistance = distance;
        closestStep = step;
      }
    });

    if (closestStep) {
      setActiveStep(closestStep.dataset.step);
    }
  }

  window.addEventListener('scroll', updateActiveStep);
  window.addEventListener('resize', updateActiveStep);
  updateActiveStep();
</script>

6.この実装が分かりやすい理由

このJavaScriptの良いところは、かなり素直なことです。

やっていることは次の3つだけです。

  1. 各STEPの位置を取得する
  2. 画面中央に最も近いSTEPを探す
  3. そのSTEPに対応する左側表示へ切り替える

つまり、
「今いちばん読まれていそうな要素」を選んでいる
だけです。

Intersection Observerを使う方法もありますが、今回のように
「中央基準で自然に切り替えたい」
場合は、まずこの方法のほうが理解しやすいことがあります。

なお、スクロールに応じて状態を更新する考え方は、
Scroll Progressの作り方
ともかなり相性が良いです。
「今どれくらい進んだか」を扱うか、「今どのステップか」を扱うかの違いだけで、発想は近いです。

7.実務で使うときの調整ポイント

実際に使うときは、次の点を調整するとかなり見やすくなります。

①STEPの高さを十分に取る

min-height: 72vh; のように、各ステップにある程度高さを持たせると、
1ステップごとの切り替わりが明確になります。

高さが短すぎると、切り替えが忙しくなり、
ユーザーが「今どこを見ているのか」を感じにくくなります。

②左側は情報を詰め込みすぎない

左側は固定されるぶん、長文を入れると読みにくくなります。
要約・図・番号・短いメッセージなど、
視覚的に一瞬で分かるもの のほうが向いています。

③スマホではstickyを無理に維持しない

モバイルでは左右2カラムが苦しいことが多いです。
今回のようにメディアクエリで1カラムにし、
stickyを外して自然に縦並びへ落とすほうが安全です。

④切り替え演出は控えめでも十分

大きなアニメーションを入れなくても、
opacity と transform の変化だけでかなり見やすくなります。

やりすぎると「内容を読むUI」ではなく「動きを見るUI」になりやすいので、
まずは情報の読みやすさを優先するのがおすすめです。

8.どんな場面で相性が良い?

Scroll Story UIは、特に次のようなコンテンツで使いやすいです。

サービス紹介

機能1、機能2、機能3…と順番に説明する場面と相性が良いです。
左側にイメージ図、右側に説明文を置く構成は定番です。

アプリの使い方説明

手順をステップ形式で見せるときに向いています。
画面遷移のように見せるデザインとも相性が良いです。

ストーリー性のあるLP

ブランドの考え方、課題、解決策、導入後の流れ、というように
順を追って読ませたいページで使いやすいです。

ポートフォリオや事例紹介

制作工程や改善プロセスを、
段階的に見せる構成にも合います。

9.単なる見た目で終わらせないために

このUIで大事なのは、
「スクロールに合わせて切り替わること」自体が目的ではない
という点です。

本当に大切なのは、
ユーザーが順番に理解しやすくなること です。

そのためには、各STEPに明確な役割を持たせる必要があります。

たとえば、

  • STEP 1 で問題提起
  • STEP 2 で特徴紹介
  • STEP 3 で具体例
  • STEP 4 で導線提示

のように、読み進める意味を作っておくと、
UIの演出が内容の理解を支えてくれます。

見た目だけ似せても、
中身の流れが弱いと「なんとなく動くけど読みにくいUI」になりやすいです。

10.実験:Scroll Story UIを体験してみよう

ここからは、実際に動きを確認するためのデモです。

今回の実験では、左右レイアウトではなく、
縦1カラム+上部sticky表示のミニマム版を使っています。

ブログのように横幅が限られている環境でも、
無理なく使えるScroll Story UIになっています。

観察ポイント

次のポイントを意識してスクロールしてみてください。

  • スクロールに応じて、上の表示がどう切り替わるか
  • 今読んでいるSTEPと、上部の表示が一致しているか
  • activeなSTEPだけ強調されることで、読みやすさがどう変わるか
  • 左右レイアウトがなくても、ストーリーとして成立しているか

特に重要なのは、

👉 「読んでいる位置」と「要約表示」が自然にリンクしているか

です。

11.まとめ

Scroll Story UIは、
スクロールを使って順番に情報を見せるUI です。

今回の実装では、

  • 左側をstickyで固定
  • 右側に複数のステップを配置
  • スクロール位置を見てアクティブSTEPを判定
  • 左側表示と右側カードを同期

という流れで作りました。

このUIの本質は、
「スクロールで動かすこと」ではなく、
「順番に理解しやすく見せること」 にあります。

Scroll Trigger AnimationやSticky Scroll Animationを、
より実践的なUIに発展させたいときにとても使いやすいパターンです。


Scroll Animationシリーズ

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA