Create Mirrored Cursor Movement with CSS and JavaScript
Tags: css, codepen, javascript, webdev
Published: 2021-10-03 17:54:43

This week's Codepen Challenge was **"Reflections"** so I created a pen where a light follows your cursor and generates and mirrors the reflection on the opposite side:

{% codepen https://codepen.io/pursuitofleisure/pen/LYLveKE %}

## Set up the light and its reflection in the HTML

```html
<div id="container">
  <div id="flashlight"></div>
  <div id="flashlight-reflection"></div>
</div>
```

Super simple: we have a container, the flashlight and the flashlight's reflection as separate divs:

## Set up the CSS and Position the Lights

```css
#flashlight,
#flashlight-reflection {
  width: 40px;
  height: 40px;
  background-color: rgba(255, 255, 255, 0.95);
  position: absolute;
  top: 50px;
  left: 50px;
  box-shadow: 0 0 20px 12px #fff;
  border-radius: 50%;
}

#flashlight-reflection {
  left: auto;
  right: 50px;
  box-shadow: 0 0 20px 12px #EB7347;
}
```

This is also pretty simple. The container contains the background color and the boundary line down the middle. The cursor's flashlight and its reflection are styled almost exactly the same except for the colors and most importantly, the `left` and `right` properties for the absolutely-positioned lights. The cursor has a `left` property, but for the reflection we're going to use the `right` property instead. This will make the JavaScript simpler later on:

## Dynamically Move the Lights with JavaScript

Let's walk through the more complicated parts of the JavaScript:

```javascript
// set boundary of coordinates to parent div
const bounds = container.getBoundingClientRect();

// Move the cursor light and reflection on the mousemove event
function moveFlashlight(e) {
  // get mouse coordinates relative to parent
  const x = e.clientX - bounds.left;
  const y = e.clientY - bounds.top;
  // move the light with the cursor and put the cursor in the center
  flashlight.style.left = `${x - 20}px`;
  flashlight.style.top = `${y - 20}px`;
  // move the reflection based on the cursor's position
  flashlightReflection.style.right = flashlight.style.left;
  flashlightReflection.style.top = flashlight.style.top;
}
```

### Find the X and Y Positions of the Cursor with `event.ClientX` and `event.ClientY`

This was actually easier than I expected. Because the lights are absolutely positioned, if we can find the X and Y coordinates of the mouse cursor, we can dynamically update the CSS position with JavaScript to follow the cursor with the `mousemove` event. This article explains how to [console.log the position of the cursor](https://www.gavsblog.com/blog/get-the-current-position-of-the-mouse-from-a-javascript-event).

### Set the Boundary to be the Parent Container
But in this scenario, our lights are divs within a parent container, and if your container is not the full-width of the screen, you're going to get inconsistent X and Y values based on the browser width. So we'll need to set the [boundaries for these values to be the parent](https://stackoverflow.com/questions/16154857/how-can-i-get-the-mouse-coordinates-relative-to-a-parent-div-javascript) to make it easier. This will always make the top left corner (0, 0).

### Update the Light's CSS (the Cursor)

Now that we have the X and Y coordinates we can move the flashlight to follow the cursor by changing the `left` and `top` values. You'll notice I'm subtracting 20px from both the X and Y; this is because the light is 40px wide and 40px high and I want the cursor to be in the center.

### Update the Light's Reflection
Since we're mirroring on the Y-axis, in terms of moving up and down, the reflection's location will always match the cursor's Y-coordinates, so we set these equal to each other.

For the X-axis, this is more complicated. As the cursor moves closer to the center or reflection line (to the right), the reflection should move closer (to the left). Conversely if the cursor moves farther away or to the left, the reflection should move to the right. I originally created a global variable to store the previous value of X, then check if the movement is increasing and if so, then to add or subtract the position of the reflection's X-position as needed. 

```javascript
// Unnecessary code
if (x > xFlashlight) {
  flashlightReflection.style.right = `${x - 1}px`;
} else {
  flashlightReflection.style.right = `${x + 1}px`;
}
```

Then I realized this code was completely unnecessary because of the CSS. Remember the cursor light is using the `left` property and the reflection is using the `right` property, and they are set to the same value for their respective properties when initialized. Therefore the actual numeric values will always be the same, so we can take the reflection's `right` value and set it equal to the cursor's `left` value.

## Conclusion

This was a fun and difficult challenge since I had never tried anything similar, but you can see how it's relatively simple to mimic and follow cursor movement with CSS and JavaScript.