要素に入るとポインターに追従する白い丸の中に文字が入る実装をしてみる(備忘録)

今回は、要素に入るとポインターに追従する白い丸の中に文字が入る実装をしていきます。一旦ポインターのシリーズはこれで最後としたいと思います。前回の記事を参考にして対応をしています。

前回の参考記事はこちら

HTMLの記述について

<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>要素に入るとポインターに追従する白い丸の中に文字が入る実装をしてみる(備忘録)</title>
  <link rel="stylesheet" href="../reset.css">
  <link rel="stylesheet" href="./style.css">
</head>

<body>
  <main>
    <div class="pointer-area"></div>
  </main>
  <script src="./style.js"></script>
</body>

</html>

これは前回と同じのため、解説は省略します。

CSSの記述について

@charset "utf-8";

/* ==========================
  初期設定
========================== */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  position: relative;
  word-wrap: break-word;
}

img {
  width: 100%;
  vertical-align: bottom;
}

/* レイアウト設定 */
main {
  margin: 80px 0;
}

.pointer-area {
  background-color: #c3512f;
  height: 400px;
  cursor: auto;
}

.custom-cursor {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  background-color: #fff;
  position: fixed;
  pointer-events: none;
  display: none;
  z-index: 1000;
  transition: opacity 0.5s ease-out, transform 0.5s ease-out;
  display: grid;
  place-items: center;
  transform: scale(0);
  opacity: 0;
}

.custom-cursor span {
  display: inline-block;
  text-align: center;
  line-height: 1;
  font-size: 12px;
  font-family: sans-serif;
}

custom-cursorの白い丸の中に文字が上下中央に配置されるよう設定しています。

JavaScriptの記述について

"use strict";

document.addEventListener("DOMContentLoaded", () => {
  // .pointer-area 要素を取得
  const pointerArea = document.querySelector(".pointer-area");

  // カスタムカーソル要素を作成
  const cursor = document.createElement("div");
  cursor.classList.add("custom-cursor");

  // カスタムカーソルの中に「VIEW」という文字を追加
  const cursorText = document.createElement("span");
  cursorText.innerText = "VIEW";
  cursor.appendChild(cursorText);

  // カスタムカーソル要素をボディに追加
  document.body.appendChild(cursor);

  // マウスとカーソルの位置を保持する変数を初期化
  let mouseX = 0,
    mouseY = 0;
  let cursorX = 0,
    cursorY = 0;
  let fadeTimeout; // フェードアウトのタイマーを保持する変数

  // マウスが pointerArea に入った時の処理
  pointerArea.addEventListener("mouseenter", () => {
    // フェードアウトタイマーが存在する場合はクリア
    if (fadeTimeout) {
      clearTimeout(fadeTimeout);
    }
    cursor.style.display = "grid"; // カスタムカーソルを表示
    setTimeout(() => {
      cursor.style.transform = "scale(1)"; // カスタムカーソルを通常サイズに拡大
      cursor.style.opacity = 1; // カスタムカーソルの透明度を1に設定
    }, 10); // 少しの遅延を追加してスムーズな表示を実現
  });

  // マウスが pointerArea 内で動いた時の処理
  pointerArea.addEventListener("mousemove", (e) => {
    // マウスの位置を取得
    mouseX = e.clientX;
    mouseY = e.clientY;

    // カーソルの初期位置が未設定の場合は設定
    if (!cursorX && !cursorY) {
      cursorX = mouseX;
      cursorY = mouseY;
    }
  });

  // マウスが pointerArea から出た時の処理
  pointerArea.addEventListener("mouseleave", () => {
    cursor.style.transform = "scale(0)"; // カスタムカーソルを縮小
    cursor.style.opacity = 0; // カスタムカーソルの透明度を0に設定(フェードアウト開始)
    fadeTimeout = setTimeout(() => {
      cursor.style.display = "none"; // フェードアウト後にカスタムカーソルを非表示に
    }, 500); // フェードアウトの時間に合わせてタイマーを設定
  });

  // カスタムカーソルをマウスに追従させるアニメーション関数
  function animate() {
    // カーソルの位置を徐々にマウスの位置に近づける
    cursorX += (mouseX - cursorX) * 0.1;
    cursorY += (mouseY - cursorY) * 0.1;

    // カスタムカーソルの位置を更新
    cursor.style.left = cursorX - 40 + "px"; // 80pxの半分で位置を補正
    cursor.style.top = cursorY - 40 + "px"; // 80pxの半分で位置を補正

    // アニメーションフレームをリクエスト
    requestAnimationFrame(animate);
  }

  // アニメーションを開始
  animate();
});

詳細はコメントアウトで記載しているとおりです。

以上で実装完了です。

また何か思いついたときに記事を書いていきたいと思います。