背景
マウスを動かした際の演習として、マウスのカーソルを追従するようついてくるマウスストーカーがあります。
このマウスストーカーを効果的に使用する事で、よりリッチな表現をする事ができると思います。
本記事ではReactを使用し、3つの円を使ったシンプルなマウスストーカーのサンプルについて解説します。
以下のgif画像が完成形です。
環境
- vite:5.0
- React:18.2.0
全体のコード
先に全体のコードとCSSを以下に記載します。
import { useEffect, useState } from "react";
import "./App.css";
const Pointer = ({ name, position }) => (
<div
className={`${name}`}
style={{
transform: `translate(${position.x}px, ${position.y}px)`,
}}
></div>
);
function App() {
// マウスの座標
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const mouseMoveListener = (event) => {
setMousePosition({ x: event.clientX, y: event.clientY });
};
// マウント時:マウスイベントリスナを追加
window.addEventListener("mousemove", mouseMoveListener);
// アンマウント時:マウスイベントリスナを削除
return () => {
window.removeEventListener("mousemove", mouseMoveListener);
};
}, []);
return (
<div className="App">
<Pointer name="pointer is-small" position={mousePosition} />
<Pointer name="pointer" position={mousePosition} />
<Pointer name="pointer is-large" position={mousePosition} />
</div>
);
}
export default App;
App.css
body {
padding: 0;
margin: 0;
background-color: aliceblue;
}
.pointer.large {
width: 50px;
height: 50px;
top: -27px;
left: -27px;
background: rgba(0, 157, 255, 0);
border: 2px solid rgba(0, 157, 255, 0.5);
border-radius: 50%;
transition: 0.5s cubic-bezier(0.075, 0.82, 0.165, 1);
}
.pointer {
width: 40px;
height: 40px;
background: rgba(0, 157, 255, 0.75);
position: fixed;
top: -20px;
left: -20px;
border-radius: 50%;
transition: 1s cubic-bezier(0.075, 0.82, 0.165, 1);
}
.pointer.small {
width: 15px;
height: 15px;
top: -7.5px;
left: -7.5px;
background: rgba(0, 119, 255, 0.5);
transition: 0.2s cubic-bezier(0.075, 0.82, 0.165, 1) transform;
}
main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
コードの詳細
以下は、ポインターを生成するコンポーネントです。
今回は3つのPointerコンポーネントを作成するので共通した1つのPointerコンポーネントを作成しておきます。
const Pointer = ({ name, position }) => (
<div
className={`${name}`}
style={{
transform: `translate(${position.x}px, ${position.y}px)`,
}}
></div>
);
Appコンポーネントでは、mousePosition
というマウスの座標を示す状態変数を作成し、
初期値として { x: 0, y: 0 } を設定しています。
useEffect
フックを使用し、マウント時にマウスの移動イベントリスナーを追加し、
アンマウントされたときにリスナーを削除しています。
function App() {
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const mouseMoveListener = (event) => {
setMousePosition({ x: event.clientX, y: event.clientY });
};
window.addEventListener("mousemove", mouseMoveListener);
return () => {
window.removeEventListener("mousemove", mouseMoveListener);
};
}, []);
最後にPointerコンポーネントを呼び出し、
異なる3つサイズのポインターを表示しています。
return (
<div className="App">
<Pointer name="pointer small" position={mousePosition} />
<Pointer name="pointer" position={mousePosition} />
<Pointer name="pointer large" position={mousePosition} />
</div>
);
Pointerに当てているCSSは以下の通りです。
3つのPointerに当てているCSS
.pointer.large {
width: 50px;
height: 50px;
top: -27px;
left: -27px;
background: rgba(0, 157, 255, 0);
border: 2px solid rgba(0, 157, 255, 0.5);
border-radius: 50%;
transition: 0.5s cubic-bezier(0.075, 0.82, 0.165, 1);
}
.pointer {
width: 40px;
height: 40px;
background: rgba(0, 157, 255, 0.75);
position: fixed;
top: -20px;
left: -20px;
border-radius: 50%;
transition: 1s cubic-bezier(0.075, 0.82, 0.165, 1);
}
.pointer.small {
width: 15px;
height: 15px;
top: -7.5px;
left: -7.5px;
background: rgba(0, 119, 255, 0.5);
transition: 0.2s cubic-bezier(0.075, 0.82, 0.165, 1) transform;
}
Pointerが動く速度を調整する方法
今回は3つのPointer
を作成しました。
3つとも同じスピードで動かすよりも、
それぞれのPointer
が異なるスピードで動いた方が
マウスストーカーとしてはリッチに見えそうな気がします。
(個人の感想です。)
その場合は、以下のようにCSSのtransition
プロパティの秒数を変える事で、
マウスを追従するスピードを変化させる事ができます。
CSS
.pointer.large {
transition: 0.5s cubic-bezier(0.075, 0.82, 0.165, 1);
}
.pointer {
transition: 1s cubic-bezier(0.075, 0.82, 0.165, 1);
}
.pointer.small {
transition: 0.2s cubic-bezier(0.075, 0.82, 0.165, 1) transform;
}
実行結果
以下のようにマウスの動きを追従するポインターを作成できました。
さらに大きさ、色、透過度等を調整する事でサイトにあったポインターを作成する事ができると思います。