CURSOR

by davidxmartins

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>

<div class="cursor">
  <div class="cursor__ball cursor__ball--big">
    <svg height="30" width="30">
      <circle cx="15" cy="15" r="12" stroke-width="0"></circle>
    </svg>
  </div>

  <div class="cursor__ball cursor__ball--small">
    <svg height="10" width="10">
      <circle cx="5" cy="5" r="4" stroke-width="0"></circle>
    </svg>
  </div>
</div>

<div class="example">

<div class=white>
  <a class="hoverable">I'M A LINK</a>
</div>

<div class=black>
  <a class="hoverable">I'M A LINK</a>
</div>

</div>

<br><br>


<ul>
<li>Any <b><a src="#">link</a></b> will have this cursor effect applied to it automatically.</li>
<li>The effect uses blending mode difference.</li>
<li>The cursor falls back to default, and it's cancelled on small touch devices.</li>
</ul>

CSS

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  height: 100vh;
  cursor: none;
  margin: 0;
  background: white;
}

body .cursor {
  pointer-events: none;
}

body .cursor__ball {
  position: fixed;
  top: 0;
  left: 0;
  width: 50px;
  height: 50px;
  mix-blend-mode: difference;
  z-index: 1000;
}

body .cursor__ball circle {
  fill: #f7f8fa;
  background-position: center center;
}


/* IRRELEVANT STYLES */

.example {
  display: flex;
  justify-content: center; /* Center items horizontally */
  align-items: center;     /* Center items vertically */
  height: auto;           /* Optional: full viewport height for vertical centering */
  width: 100%;
}
ul {
  display: block;         /* Ensure the ul behaves as a block-level element */
  margin: 0 auto;         /* Center the ul horizontally */
  padding-left: 0;        /* Remove default padding on ul */
  text-align: left;       /* Align text inside ul items to the left */
  list-style-position: inside; /* Ensure bullets are inside the content flow */
  width: fit-content;     /* Ensure the ul only takes up as much width as its content */
}

/* Style list items */
ul li {
  list-style-type: disc;  /* Use disc bullets */
  margin-bottom: 10px;    /* Add spacing between items */
  font-family: Arial, sans-serif; /* Set a font for better readability */
  font-size: 16px;        /* Set a readable font size */
  color: #333;            /* Set a color for the text */
}

.black{
  background: black;
  color: white;
  float: left;
  margin: 50px;
  padding: 50px;
}

JavaScript

// Function to check if the device is touch-based
function isTouchDevice() {
    return 'ontouchstart' in window || navigator.maxTouchPoints;
}

// Function to check if the screen is small
function isSmallScreen() {
    return window.innerWidth <= 768;
}

// Function to initialize or hide the cursor effect
function handleCursorEffect() {
    const cursor = document.querySelector(".cursor");

    // Check if cursor should be hidden
    if (isTouchDevice() || isSmallScreen()) {
        cursor.style.display = 'none';
        return;
    }

    cursor.style.display = 'block'; // Show cursor if conditions are met

    // Select all <a> tags
    const $bigBall = document.querySelector(".cursor__ball--big");
    const $smallBall = document.querySelector(".cursor__ball--small");
    const $hoverables = document.querySelectorAll("a"); // Select all <a> tags

    function onMouseMove(e) {
        TweenMax.to($bigBall, 0.4, {
            x: e.pageX - 15,
            y: e.pageY - 15
        });
        TweenMax.to($smallBall, 0.1, {
            x: e.pageX - 5,
            y: e.pageY - 7
        });
    }

    function onMouseHover() {
        TweenMax.to($bigBall, 0.3, {
            scale: 3,
            top: 20,
            left: 20
        });
    }

    function onMouseHoverOut() {
        TweenMax.to($bigBall, 0.3, {
            scale: 1,
            top: 0,
            left: 0
        });
    }

    document.body.addEventListener("mousemove", onMouseMove);
    $hoverables.forEach(el => {
        el.addEventListener("mouseenter", onMouseHover);
        el.addEventListener("mouseleave", onMouseHoverOut);
    });
}

// Run the cursor effect initialization when DOM is fully loaded
document.addEventListener('DOMContentLoaded', handleCursorEffect);

// Optional: Re-check cursor effect on window resize
window.addEventListener('resize', handleCursorEffect);