PractiX Code Lab

Next.js マウスに反応するパララックス表現をReactで作る

Share this post

🚪はじめに

こんにちは、管理人のTKGです。

今回は、ポートフォリオサイト制作の一環として導入した「パララックスアニメーション」についてご紹介します。

パララックス効果とは何か、その視覚的なインパクトがどのような効果をもたらすのか、また、どのように実装するのかについてわかりやすく解説していきます。

「サイトに奥行き感を出したい」「ちょっとした動きで印象を強めたい」という方におすすめの内容です。


🎯想定読者

  • パララックスアニメーションとは何か
  • Next.js でのパララックス効果の実装方法
  • 実装中につまずいたポイントと対処法

📘本記事でわかること

  • Next.jsでサイトを開発している方 - Webに動きを取り入れたいデザイナー/エンジニア

💡 パララックスとは?

パララックス(Parallax)とは、視差効果とも呼ばれ、スクロールやユーザー操作に応じて背景と前景の移動速度に差をつけ、体感や奥行きを演出する表現技法です。

たとえば:

  • 背景画像はゆっくり、前面のテキストは速く動く
  • スクロールに合わせてコンテンツが浮き出てくるように表示される

この効果を加えることで、視覚的な印象の強化UXの向上につながります。


⚙️ 実装の準備

使用技術

  • Next.js(App Router構成)
  • Tailwind CSS(スタイル調整)

✍️ 実装ステップ:マウス連動型パララックスの実装

今回実装したのは、マウスの動きに応じて要素が微妙に移動することで、画面に奥行きやインタラクション性を与えるパララックス効果です。

スクロール連動型とは異なり、「ユーザーが画面上でマウスを動かすと、背景やコンテンツがわずかに追従する」ことで、より動的でゲームライクな印象を与えることができます。

"use client";

import { createContext, useContext, useEffect, useState } from "react";

const ParallaxContext = createContext({ x: 0, y: 0 });

export function ParallaxProvider({ children }: { children: React.ReactNode }) {
  const [offset, setOffset] = useState({ x: 0, y: 0 });

  useEffect(() => {
    const handleMouseMove = (e: MouseEvent) => {
      const { innerWidth, innerHeight } = window;
      const x = (e.clientX / innerWidth - 0.5) * 2;
      const y = (e.clientY / innerHeight - 0.5) * 2;
      setOffset({ x, y });
    };

    window.addEventListener("mousemove", handleMouseMove);
    return () => window.removeEventListener("mousemove", handleMouseMove);
  }, []);

  return (
    <ParallaxContext.Provider value={offset}>
      {children}
    </ParallaxContext.Provider>
  );
}

export function useParallax() {
  return useContext(ParallaxContext);
}


💡 仕組み解説

  • mousemove イベントでマウス座標を取得
  • x, y1 ~ +1 の範囲で画面中心を基準に正規化
    • e.clientX / innerWidth で 0〜1 の範囲に正規化しています
    • それを中心基準にずらすため -0.5
    • さらに 2 を乗算することで範囲を -1 ~ +1 にスケーリング
  • ParallaxContext でアニメーションに必要な値をコンポーネントツリーへ提供
  • useParallax() を使うことで任意の要素にアニメーション効果を加えることが可能

🧪 使用例

"use client";
import { motion } from "framer-motion";
import { useParallax } from "@/components/ParallaxProvider";

export default function ParallaxItem() {
  const { x, y } = useParallax();

  return (
    <motion.div
      style={{
        transform: `translate(${x * 20}px, ${y * 20}px)`,
      }}
      className="w-40 h-40 bg-blue-500 rounded-lg shadow-md"
    >
      {/* 中身 */}
    </motion.div>
  );
}

※要素がマウスに反応して動くようになります。


🧱 詰まりポイントと対応

✅ 「mousemove」で毎フレーム更新される

影響の少ない範囲に限定し、Framer Motionで自然な動きに変換(spring補間)するのも一案。

マウス座標はイベント発火のたびに即座に変化します。そのまま使うと動きがガクガクして見えたり、急激すぎる移動に感じられます。

そのため、Framer Motionの useSpring を使って補間することで、以下のような自然でスムーズな動きに変換できます:

import { useSpring } from "framer-motion";

const smoothX = useSpring(x, { stiffness: 50, damping: 20 });
const smoothY = useSpring(y, { stiffness: 50, damping: 20 });

※今回は未実装です

✅ 子要素で useParallax() を使うと毎回レンダーが走る

// これだと非推奨(子ごとにuseParallax())
function Child() {
  const { x, y } = useParallax();
  return <motion.div style={{ transform: `translate(${x}px, ${y}px)` }} />;
}
  • 要素が多ければ多いほどパフォーマンスに影響
  • 複数コンポーネントが毎フレーム再描画され、CPU/GPU負荷が高まる
  • 上記のような無駄な再レンダリングを防ぐため、useParallax() はできるだけ親要素で使い、子へpropsとして渡す設計が望ましいです。
function Parent() {
  const { x, y } = useParallax();
  return (
    <>
      <Child x={x} y={y} />
      <AnotherChild x={x} y={y} />
    </>
  );
}

🛠 応用アイデア

  • レイヤーを複数重ねて、奥行きの異なるパララックスを表現
  • useScrollを複数組み合わせて、複雑な動きを演出

✏️ まとめ

マウス連動型のパララックスは、UXにリッチさを加え、訪問者の印象に残るサイトを作るうえで非常に効果的です。視覚的な没入感や動きのある表現を追求したい場合に最適です。


🚀成果物リンク

👉Takashi Sekiguchi Portfolio

Share this post