JSFiddle - React, Tailwind, and code Playground

by HDL52

HTML

<ul class="menu-hover-image">
  <li class="menu-item">
    <a href="#">
      <h1>Home</h1>
      <span># 1</span>
    </a>
  </li>
  <li class="menu-item">
    <a href="#">
      <h1>Projects</h1>
      <span># 2</span>
    </a>
  </li>
  <li class="menu-item">
    <a href="#">
      <h1>Blogs</h1>
      <span># 3</span>
    </a>
  </li>
  <li class="menu-item">
    <a href="#">
      <h1>About</h1>
      <span># 4</span>
    </a>
  </li>
  <div class="cursor"></div>
</ul>

SCSS

@import url("https://fonts.googleapis.com/css?family=Lora:400,400i,700");

body {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  background: #121212;
  overflow: hidden;
}

.menu-hover-image {
  position: relative;
  width: 56rem;
  margin-bottom: 12rem;
  font-family: Lora, serif;
  list-style-type: none;

  .cursor {
    position: absolute;
    top: -50%;
    left: -25%;
    z-index: -1;
    width: 600px;
    height: 400px;
    background-image: linear-gradient(120deg, #a1c4fd 0%, #c2e9fb 100%);
    background-position: 50% 50%;
    background-size: cover;
    opacity: 0;
  }

  .menu-item {
    $menu-image-urls: url('https://raw.githubusercontent.com/Hongda-OSU/PicGo-2.3.1/master/imgied0v0dgsgyqeoh7804b0ca54buj0qd.jpg'),
      url('https://raw.githubusercontent.com/Hongda-OSU/PicGo-2.3.1/master/imge39twvhffwemdsipqncbwko5vayrxgd.jpg'),
      url('https://raw.githubusercontent.com/Hongda-OSU/PicGo-2.3.1/master/imgodr8vukcwco0h34p0ngc84462vs454j.jpg'),
      url('https://raw.githubusercontent.com/Hongda-OSU/PicGo-2.3.1/master/imgj1udos782ybmzugwd1ltkozc9zxj3gz.jpg');

    @for $i from 1 through 4 {
      &:nth-child(#{$i}):hover~.cursor {
        background-image: nth($menu-image-urls, $i);
      }
    }

    a {
      display: flex;
      justify-content: space-between;
      align-items: center;
      width: 100%;
      text-decoration: none;
      color: white;
      border-bottom: 1px solid rgba(255, 255, 255, 0.3);
      mix-blend-mode: difference;
      transform: translate3d(0, 0, 0);  // just make "mix-blend-mode" work properly.
    }
  }
}

JavaScript

// https://codepen.io/alphardex/pen/OJPmQGz

let menuItems = document.querySelectorAll(".menu-hover-image .menu-item")
let cursor = document.querySelector(".menu-hover-image .cursor")
let getXY = (e) => [e.clientX, e.clientY]

menuItems.forEach((menuItem) => {
  // use mouseenter and mouseleave to toggle cursor since they won't bubble!
  menuItem.addEventListener("mouseenter", (e) => {
    let [x, y] = getXY(e)
    cursor.animate(
      [
        {
          opacity: 0,
          transform: `translate(${x}px, ${y}px) scale(0)`,
        },
        {
          opacity: 1,
          transform: `translate(${x}px, ${y}px) scale(1)`,
        },
      ],
      { duration: 300, fill: "forwards" },
    )
    
    menuItem.addEventListener("mouseleave", (e) => {
      let [x, y] = getXY(e)
      cursor.animate(
        [
          {
            opacity: 1,
            transform: `translate(${x}px, ${y}px) scale(1)`,
          },
          {
            opacity: 0,
            transform: `translate(${x}px, ${y}px) scale(0)`,
          },
        ],
        { duration: 300, fill: "forwards" },
      )
    })
  })
  
  // move the cursor when mouse moves.
  menuItem.addEventListener("mousemove", (e) => {
    let [x, y] = getXY(e)
    cursor.animate(
      [
        {
          transform: `translate(${x}px, ${y}px)`,
        },
        {
          transform: `translate(${x}px, ${y}px)`,
        },
      ],
      { duration: 500, delay: 50, fill: "forwards" },
    )
  })
})