WEBTODESIGN

バニラJSでマウスストーカーを実装する

マウスポインターに何かついてくるーーーー

マウスストーカーの実装メモ。今回実現した機能は以下です。

  • ちょっと遅れて追従する
  • 画面外に出ると消える
  • ホバー時に変形する
  • スマホでは非表示

HTMLを用意

まずはマウスストーカーになる部分をHTMLで用意します。

<div class="mousestalker">
    <div></div>
</div>

divを入れ子にしているのは、ホバーの際に自由にアニメーションを入れるためです。
マウスストーカーはtransformで動かすので、ホバーの時にscaleで拡大縮小したい場合、挙動が被ってしまうので入れ子にする必要がありました。なので、ホバーで色を変えるだけなどの場合は入れ子にする必要はないです。

CSSで見た目を整える

次に、CSSでマウスストーカーの見た目を整えます。

.mousestalker{
    position: fixed;
    top: -10px;/* マウスポインターに対しての位置 */
    left: -10px;/* マウスポインターに対しての位置 */
    pointer-events: none;
    z-index: 1000;/* 常に手前に */
    transition: .2s;
    will-change: transform;/* 動く処理の負荷軽減 */
    transition-timing-function: ease-out;/* ちょっと遅れる部分 */
}
.mousestalker div{
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background-color: #000;
    transition: transform .3s;
}
.mousestalker.hover div{
    transform: scale(.5);/* ホバー時に小さくなる */
}

ポイントは以下。

  • position: fixedで位置を固定する
  • z-index: 1000で常に手前に表示する
  • transition-timing-functionをつけることで少し遅れてついてくる

position: fixedでマウスストーカーの位置を画面上に固定してJSで位置を動かすことで、マウスポインターについてきているかのように見せることができます。

transition-timing-functionが、少し遅れて追従する指示の部分なります。ちょっと遅れるのがなんか重いサイトに感じて微妙なんだよね、、、っていう場合はtransition-timing-functionをなくせばOKです。

JSで動かす

最後にJSでマウスストーカーを動かします。以下は全部のせの状態のJSです。

const pointer = document.querySelector('.mousestalker');
const mousestailkerEvent = () => {
    document.addEventListener('mousemove', e => {
        pointer.style.transform = 'translate(' + e.clientX + 'px, ' + e.clientY + 'px)';
    });
    //カーソルがウィンドウ外の場合非表示
    document.body.addEventListener('mouseenter', () => pointer.style.opacity = 1, false);
    document.body.addEventListener('mouseleave', () => pointer.style.opacity = 0, false);
    //ホバー時に変形(ホバー時に「hover」クラスを付与)
    const links = document.querySelectorAll('a');
    links.forEach( e => {
    e.addEventListener('mouseover', () => pointer.classList.add('hover'));
        e.addEventListener('mouseout', () => pointer.classList.remove('hover'));
    });
}
document.getElementsByTagName('body')[0].setAttribute('ontouchstart','');
let touch = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
if(touch){
    pointer.style.display = 'none';//タッチデバイスの場合はマウスストーカー非表示
} else {
     window.addEventListener('DOMContentLoaded', mousestailkerEvent);//タッチデバイスでない場合はマウスストーカー発動
}

動かしている部分

以下の部分があれば最低限動きます。マウスが動いているときに画面の上と左からの位置へマウスストーカーを移動するという処理です。

document.addEventListener('mousemove', e => {
    pointer.style.transform = 'translate(' + e.clientX + 'px, ' + e.clientY + 'px)';
});

遅れてついてくるのはCSSの以下の部分。遅れ具合などもCSSで調整できます。transition-timing-functionをなくせば、遅れずについてきます。

.mousestalker{
    transition: .2s;
    transition-timing-function: ease-out;
}

画面外では非表示にする

マウスがウィンドウ外に行ったときに画面の端にマウスストーカーが残っているのが嫌だったので、マウスが画面外に行った時はマウスストーカーを非表示にする処理を加えました。

document.body.addEventListener('mouseenter', () => pointer.style.opacity = 1, false);
document.body.addEventListener('mouseleave', () => pointer.style.opacity = 0, false);

カッコいいサイトなのにこの処理をしてないサイトが結構多くて個人的に気になるので、マウスストーカーを実装する際は是非画面外に出ると消える処理も是非に、、、!

ホバーで変形する

ホバーしているときに「hover」クラスを付与して変形させる処理も追加しました。aタグにホバーしたら「hover」クラスを付与、外れたら「hover」クラスを外す処理です。

const links = document.querySelectorAll('a');
links.forEach( e => {
    e.addEventListener('mouseover', () => pointer.classList.add('hover'));
    e.addEventListener('mouseout', () => pointer.classList.remove('hover'));
});

これはクラスの付け外しをしているだけなので、アニメーションはCSSで追加します。

タッチデバイスでは無効化

そして最後に、タッチデバイスではマウスストーカーを表示しない処理。タッチデバイスかどうかを認識して、タッチデバイスの場合はマウスストーカーを非表示、そうでない場合はマウスストーカーのイベントを実行するようにしています。

document.getElementsByTagName('body')[0].setAttribute('ontouchstart','');
let touch = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
if(touch){
    pointer.style.display = 'none';//タッチデバイスの場合はマウスストーカー非表示
} else {
     window.addEventListener('DOMContentLoaded', mousestailkerEvent);//タッチデバイスでない場合はマウスストーカー発動
}

また、外部ライブラリで生成されたページネーションなどにホバーした際もホバーが作動して欲しかったので、DOMContentLoadedのタイミングで実行しています。(普通に初期化すると、外部ライブラリで生成される前に実行されてしまい、リストにうまく取得できませんでした。)

おわりに

これで

  • ちょっと遅れて追従する
  • 画面外に出ると消える
  • ホバー時に変形する
  • スマホでは非表示

というマウスストーカーが実装できました!

マウスストーカーはサイトが重く感じることもあるので、ご利用は計画的に😗