【GSAP】UIをリッチに!マウスに吸い付くマグネティックボタンの作り方
最近のモダンなWebサイトでよく見かける、マウスカーソルを近づけるとフワッと吸い付くように動く「マグネティックボタン」。 ユーザーの目を惹きつけるリッチなUIですが、「実装が難しそう」「スマホでの誤動作が心配」と思う方も多いのではないでしょうか。
今回は、アニメーションライブラリの GSAP を活用して、このマグネティックボタンをシンプルに実装する方法をご紹介します!
GSAPの機能をフル活用することで、「PC(マウス操作)環境の時だけ有効にする」「ぽよんっと自然に弾んで元に戻る」といった制御が、驚くほど短いコードで実現できます。コピペで動くデモも用意したので、ぜひPCからマウスでホバーして動きを確かめてみてください!
デモ動作
See the Pen GSAPで作るマグネティックボタン by mikanbako (@mikanbako) on CodePen.
demo: GSAPで作るマグネティックボタン
実装コードの紹介
【HTML】
<div class="l-wrap">
<h2>マグネティックボタン デモ</h2>
<div class="p-magnetic-wrap">
<!-- マグネティック効果をつけるボタン本体 -->
<a href="#" class="c-magnetic-button js-magnetic-button">
<span class="c-magnetic-button__text">Hover Me!</span>
</a>
</div>
</div>
【CSS】
.l-wrap {
color: #3e3e3e;
padding: 40px 20px;
max-width: 800px;
margin: 0 auto;
text-align: center;
}
h2 {
color: #1bb4d4;
font-size: 16px;
margin-bottom: 60px;
}
/* ボタンを配置するエリア */
.p-magnetic-wrap {
display: flex;
justify-content: center;
align-items: center;
}
/* ボタンの装飾 */
.c-magnetic-button {
display: flex;
justify-content: center;
align-items: center;
width: 160px;
height: 160px;
border-radius: 50%;
background: #1bb4d4;
color: #fff;
font-size: 18px;
font-weight: bold;
box-shadow: 0 10px 20px rgba(27, 180, 212, 0.3);
/* 【重要】transform(移動)のアニメーションはGSAPに任せるため、
CSSのtransitionは背景色や影などの「見た目」だけに限定します! */
transition: background-color 0.3s, box-shadow 0.3s;
}
/* ホバー時の見た目の変化(CSSで担当) */
.c-magnetic-button:hover {
background: #1698b3;
box-shadow: 0 15px 25px rgba(27, 180, 212, 0.5);
}
/* テキストがマウスイベントの邪魔をしないようにする */
.c-magnetic-button__text {
pointer-events: none;
}
【JavaScript】
const magneticButton = document.querySelector('.js-magnetic-button');
const mm = gsap.matchMedia();
// マウスが使えるPC環境の時だけ実行する(スマホやタブレットでは無視される)
mm.add("(hover: hover) and (pointer: fine)", () => {
// マウスがボタンの上で動いた時の処理
magneticButton.addEventListener('mousemove', (e) => {
// ボタンの現在の位置とサイズを取得
const rect = magneticButton.getBoundingClientRect();
// ボタンの「中心座標」を計算
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
// マウスとボタンの中心との「距離」を計算
const distanceX = e.clientX - centerX;
const distanceY = e.clientY - centerY;
// 距離の0.3倍移動させて、自然な磁力感(吸い付き)を出す
gsap.to(magneticButton, {
x: distanceX * 0.3,
y: distanceY * 0.3,
duration: 0.3,
ease: 'power2.out'
});
});
// マウスがボタンから離れた時の処理
magneticButton.addEventListener('mouseleave', () => {
// 元の位置(x: 0, y: 0)に戻す
gsap.to(magneticButton, {
x: 0,
y: 0,
duration: 0.5,
ease: 'elastic.out(1, 0.3)' // ぽよんっと弾ませる
});
});
});
解説・GSAPを使うメリット
このようなマウス追従の処理をすべて素のJavaScript(バニラJS)とCSSの transition だけで実装しようとすると、いくつか面倒な問題が発生します。今回GSAPを採用したのには、以下のような明確なメリットがあるからです!
gsap.matchMedia() でPC限定の制御が簡単!
// マウスが使えるPC環境の時だけ実行する(スマホやタブレットでは無視される)
mm.add("(hover: hover) and (pointer: fine)", () => {
...
});
マグネティックボタンはマウスのホバーを前提としているため、タップ操作のスマートフォンでは不具合の原因になることがあります。 gsap.matchMedia() で (hover: hover) and (pointer: fine) を指定するだけで、「精度の高いポインター(マウス)が使える環境のみ」で安全にアニメーションを発火させることができます。
ガタつきのない滑らかな移動(インラインスタイルの管理)
CSSの transition で transform: translate() を動かすと、マウスの動きにアニメーションが追いつかず、ガタガタと震えるような不自然な挙動になりがちです。GSAPの to() メソッドを使えば、毎フレームごとの移動(x, y)を最適化して計算してくれるため、非常に滑らかにカーソルに追従します。
豊富な ease(イージング)でリッチな表現が可能
// マウスがボタンから離れた時の処理
magneticButton.addEventListener('mouseleave', () => {
// 元の位置(x: 0, y: 0)に戻す
gsap.to(magneticButton, {
x: 0,
y: 0,
duration: 0.5,
ease: 'elastic.out(1, 0.3)' // ぽよんっと弾ませる
});
});
マウスが離れた際、元の位置に戻る動きに ease: 'elastic.out(1, 0.3)' を指定しています。これにより、バニラJSやCSSだけでは実装が複雑な「ゼリーのようにぽよんっと弾む」ような物理的な跳ね返り表現が、たった1行で実現できます!
まとめ
今回は、GSAPを活用したマグネティックボタンの実装方法をご紹介しました。
要素の座標計算といった数学的な部分はJavaScriptの基本メソッドを使いますが、実際の「動きの滑らかさ」や「デバイスごとの出し分け」「複雑なイージング」といった面倒な部分はGSAPがすべて綺麗に担当してくれます。
こうした細かいUIのこだわりが、Webサイト全体のクオリティや「触り心地の良さ」に直結します。ぜひ自身のサイトなどでも、この技術を活用してみてください!