スクロール速度で変わるUIの作り方【JavaScriptで気持ちいい演出を実装】

Scroll Velocity Animationのアイキャッチ画像

スクロール連動UIというと、要素がフェードしたり、少し動いたりする実装を思い浮かべることが多いです。
ただ、実際のUIでは「どこまでスクロールしたか」だけでなく、どのくらいの速さでスクロールされたかによって印象が変わることもあります。

たとえば、速くスクロールしたときは少し流れるように見せて、ゆっくり止まったときは静かに落ち着かせる。
こうした表現を入れるだけで、UIにほんの少し「手触り」が生まれます。

この記事では、Scroll Velocity Animation の基本的な考え方と、JavaScriptで実装する方法を初心者向けに整理していきます。
最後には、実際に触って確認できる実験デモの考え方も紹介します。

この記事でわかること

  • スクロール速度とは何か
  • scrollY の差分から速度を求める考え方
  • 速度に応じて UI の見た目を変える方法
  • Scroll Reveal や Scroll Story とは少し違う演出の作り方

1.Scroll Velocity Animationとは?

Scroll Velocity Animation は、スクロール位置そのものではなく、スクロールの速さを使って見た目を変えるUI表現です。

よくあるスクロール演出は、次のように「位置」を基準にしています。

  • 画面に入ったらフェードインする
  • 一定位置まで来たら固定する
  • セクションごとに内容を切り替える

一方で Scroll Velocity Animation は、次のように「速度」を基準にします。

  • 速くスクロールしたときだけ少し流す
  • スクロールが止まりそうになると元に戻す
  • 一時的にぼかしや移動量を強める

つまり、スクロールの結果ではなく、スクロール中の勢いを使うUIです。

2.なぜスクロール速度を使うのか

理由はシンプルで、動きに少しだけ人間らしい反応を加えられるからです。

スクロール量だけで制御すると、見た目は正確でも少し機械的になりやすいです。
そこに速度の情報を足すと、動きに「慣性っぽさ」や「勢い」が出ます。

たとえば次のような場面で相性が良いです。

  • カード一覧の軽い追従演出
  • ヒーロー画像の流れ感
  • テキストや背景の微妙なズレ
  • スクロール中だけ少しブラーを入れる表現

派手すぎる必要はなく、ほんの少しだけ変化を足すくらいがちょうどよいです。

3.基本の考え方

スクロール速度は、ざっくり言うと次のように求められます。

現在のスクロール位置 – ひとつ前のスクロール位置

たとえば、

  • 前フレームの scrollY が 100
  • 今の scrollY が 112

なら、差分は 12 です。
この差分が大きいほど「速くスクロールした」と考えられます。

逆に、

  • 前フレームが 300
  • 今が 302

なら差分は 2 なので、ゆっくり動いたことになります。

この差分をそのまま使ってもいいですが、実際には少し強すぎたりガタついたりするので、値をなめらかに補間して使うのが基本です。

4.実装の全体像

今回の流れはかなりシンプルです。

  1. 現在のスクロール位置を取得する
  2. 前回との差分を求める
  3. その値を目標速度として持つ
  4. 実際に使う速度は easing 的になめらかに追従させる
  5. transform や blur に反映する

この考え方なら、Scroll Trigger や Scroll Reveal よりも小さな構成で作れます。

HTML

まずは動かす要素を用意します。
今回は、中央に1枚のカードがあり、そのカードがスクロール速度に応じて少し上下し、わずかに傾く構成にします。

<section class="hero">
  <div class="velocity-card" id="velocityCard">
    <p class="label">Scroll Velocity</p>
    <h1>Move with speed</h1>
    <p class="desc">
      The card reacts to how fast you scroll, not just how far.
    </p>
  </div>
</section>

<section class="spacer"></section>
<section class="spacer"></section>
<section class="spacer"></section>

上の spacer は、スクロールできる余白を確保するためのものです。
実験として確認するときは、ある程度縦の長さがある方がわかりやすいです。

CSS

見た目はできるだけシンプルにして、速度の変化が分かりやすいようにします。

* {
  box-sizing: border-box;
}

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

.hero {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
}

.velocity-card {
  width: min(560px, 92vw);
  padding: 32px;
  border-radius: 24px;
  background: linear-gradient(180deg, #1c2230 0%, #141922 100%);
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.28);
  transform: translateY(0px) rotate(0deg);
  filter: blur(0px);
  will-change: transform, filter;
}

.label {
  margin: 0 0 12px;
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.7;
}

.velocity-card h1 {
  margin: 0 0 12px;
  font-size: clamp(2rem, 4vw, 3.5rem);
  line-height: 1.1;
}

.desc {
  margin: 0;
  color: rgba(255, 255, 255, 0.72);
  line-height: 1.7;
}

.spacer {
  height: 100vh;
}

ここでは will-change をつけて、transform と filter が変わることをブラウザに伝えています。
大きな最適化ではありませんが、こうした動きのあるUIではよく使われます。

JavaScript

次に、スクロール速度を取得してカードへ反映します。

const card = document.getElementById("velocityCard");

let lastScrollY = window.scrollY;
let targetVelocity = 0;
let currentVelocity = 0;

function updateVelocity() {
  const currentScrollY = window.scrollY;

  targetVelocity = currentScrollY - lastScrollY;
  lastScrollY = currentScrollY;

  requestAnimationFrame(updateVelocity);
}

function render() {
  currentVelocity += (targetVelocity - currentVelocity) * 0.12;

  const translateY = currentVelocity * 1.5;
  const rotate = currentVelocity * 0.08;
  const blur = Math.min(Math.abs(currentVelocity) * 0.08, 6);

  card.style.transform = `translateY(${translateY}px) rotate(${rotate}deg)`;
  card.style.filter = `blur(${blur}px)`;

  targetVelocity *= 0.9;

  requestAnimationFrame(render);
}

updateVelocity();
render();

5.コードの見方

ここでやっていることを順番に整理します。

①前回のスクロール位置を覚える

let lastScrollY = window.scrollY;

前のフレームでどこにいたかを記録しておきます。
これがないと差分が取れません。

②現在位置との差分を取る

targetVelocity = currentScrollY - lastScrollY;

これが速度の元になります。下に速くスクロールすれば大きめの正の値になり、逆方向なら負の値になります。

③いきなり使わず、なめらかに追従させる

currentVelocity += (targetVelocity - currentVelocity) * 0.12;

この部分がかなり大事です。

差分をそのまま見た目に使うと、動きがガタガタしやすくなります。
そこで、今の値を少しずつ目標値へ近づけています。

この考え方は、これまでの easing や Interpolation の記事ともつながります。
補間の基礎を先に整理したい場合は、以下の記事もあわせて読むと理解しやすいです。

④transform と blur に変換する

const translateY = currentVelocity * 1.5;
const rotate = currentVelocity * 0.08;
const blur = Math.min(Math.abs(currentVelocity) * 0.08, 6);

速度の値そのものを直接見せるのではなく、
移動量回転量ぼかし量に変換しています。

ここはデザイン次第で自由に変えられます。

たとえば、

  • 背景だけ少し動かす
  • テキストだけ傾ける
  • 画像だけブラーをかける

といった応用も可能です。

6.なぜ requestAnimationFrame を使うのか

こうしたアニメーションでは、scroll イベントのたびに直接スタイルを更新するより、
requestAnimationFrame の中で描画をまとめた方が扱いやすいです。

理由は、ブラウザの描画タイミングに合わせて更新できるからです。
毎回イベントの中で全部を処理すると、状態の管理がばらけやすくなります。

requestAnimationFrame の基本がまだあいまいな場合は、こちらの記事もおすすめです。

7.Scroll Reveal や Scroll Story との違い

Scroll Velocity Animation は、これまでのスクロール系UIと似ているようで少し違います。

Scroll Reveal

要素が画面に入ったかどうかを基準にすることが多いです。
「現れ方」を見せる演出です。

Scroll Story

スクロール位置に応じて段階的に内容を切り替えます。
「進行」を見せる演出です。

Scroll Velocity Animation

スクロールの速さに反応します。
「勢い」を見せる演出です。

そのため、主役というよりは、他のUIに重ねて使う補助的な演出として相性が良いです。

8.実装するときの注意点

①やりすぎない

速度に対して移動量やブラーが大きすぎると、読みにくくなります。
特にテキストに強い blur をかけると、一気に使いにくくなります。

②transform を優先する

位置を動かすなら top や margin より、まず transform を使う方が扱いやすいです。
レイアウト全体への影響を減らしやすくなります。

③常に元へ戻る設計にする

スクロールが止まったあとも変形が残ると、不自然に見えます。
今回のように targetVelocity *= 0.9 のような減衰を入れて、自然にゼロへ近づけるのが基本です。

④補間を入れる

差分の生値は思った以上に荒れます。
そのまま使うより、少しなめらかにしてから見た目へ反映した方がきれいです。

9.どんなUIに向いている?

Scroll Velocity Animation は、次のような用途に向いています。

  • ファーストビューのカードやビジュアル
  • 背景レイヤーの微妙な流れ
  • ギャラリーや作品一覧の質感づけ
  • ミニマルなサイトの「静かな動き」
  • インタラクティブな実験ページ

逆に、フォームや本文のように読みやすさが最優先の場所では、強く入れすぎない方が安全です。

10.実験:スクロール速度でカードの質感を変える

中央のカードがスクロールの速さに応じて少し動き、わずかに傾き、軽くブラーがかかります

見るポイントは「どこまでスクロールしたか」ではなく、どのくらい勢いよく動かしたかで見た目が変わることです。

観察ポイント

  • ゆっくりスクロールすると変化はかなり小さい
  • 速く動かすとカードが少し流れる
  • スクロールを止めると自然に元へ戻る
  • 下方向と上方向で傾き方が変わる

このタイプの演出は、単体では派手すぎないのに、ページ全体の印象を少しだけ上げてくれます。
「何が起きているか説明しづらいけれど、なんとなく気持ちいい」というUIを作りたいときに便利です。

11.まとめ

Scroll Velocity Animation は、スクロール位置ではなくスクロール速度を使って見た目を変えるUI表現です。

実装の流れはそこまで難しくありません。

  • スクロール位置の差分を取る
  • 速度として保持する
  • 補間してなめらかにする
  • transform や blur に反映する

これだけでも、かなりそれっぽい動きが作れます。

Scroll Reveal や Scroll Story のような「進行ベース」の演出と組み合わせると、
UIの表現にもう一段階深さを出せます。

まずはカード1枚、背景1レイヤーくらいの小さな実験から始めて、
やりすぎない速度演出を試してみてください。


Scroll Animationシリーズ

コメント

コメントを残す

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

CAPTCHA