I’m trying to make a flashlight effect that will reveal a content inside a black box. So a flashlight should be a circle centered in place of a cursor and bigger than my custom img cursor which is also centered (exactly like in the current solution). The issue is that I cannot achieve the reveal of a content functionality and ended up with that radial-gradient
css property which does nothing in case of revealing. Made it to visualize how it should look like. Could anyone help?
This is a reproduction of my code. The img in place of a cursor is random but normally it would be a flashlight img.
Link to a sandbox – https://codesandbox.io/s/javascript-forked-6v9rcm?file=/src/index.js
const box = document.querySelector(".box");
const customCursor = document.createElement("img");
customCursor.className = "custom-cursor";
customCursor.src = "https://picsum.photos/50";
const flashLight = document.createElement("div");
flashLight.className = "flashlight";
box.appendChild(customCursor);
box.appendChild(flashLight);
box.addEventListener("mousemove", (e) => {
const rect = box.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
customCursor.style.display = "block";
flashLight.style.display = "block";
customCursor.style.left = `${x - customCursor.width / 2}px`;
customCursor.style.top = `${y - customCursor.height / 2}px`;
flashLight.style.left = `${x - flashLight.offsetWidth / 2}px`;
flashLight.style.top = `${y - flashLight.offsetHeight / 2}px`;
});
box.addEventListener("mouseleave", () => {
customCursor.style.display = "none";
flashLight.style.display = "none";
});
body {
font-family: sans-serif;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.box {
display: flex;
align-items: center;
justify-content: center;
cursor: none;
width: 100%;
padding: 5rem;
background-color: #000;
overflow: hidden;
position: relative;
}
.custom-cursor {
width: 50px;
height: 50px;
position: absolute;
display: none;
z-index: 999;
pointer-events: none;
}
.flashlight {
border-radius: 50%;
width: 200px;
height: 200px;
background-image: radial-gradient(
circle,
rgba(255, 255, 255, 0.8) 0%,
rgba(255, 255, 255, 0) 100%
);
position: absolute;
}
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app">
<div class="box"><h1>Light</h1></div>
</div>
<script src="src/index.js"></script>
</body>
</html>
5
Answers
I have done some modifications to your code. Here is the final result:
Your main problem was that because the text was behind all other positioned elements, it couldn’t be detected. so we have to give it a position to bring it to the front to be discoverable.
First, you need a container on which you want to apply the flashlight effect. After that, a specific HTML structure must be implemented within the container, which, with the appropriate CSS styling, creates the "flashlight" effect. The movement of this HTML structure based on mouse events can be achieved with JavaScript. I’ve prepared two examples for you.
Solution # 1 (Local: Detecting mouse movement within the container)
Each container here is equipped with its own event listener. If we move the cursor out of the container, the "flashlight" effect disappears, and it appears when the cursor is moved inside.
Solution # 2 (Global: Detecting mouse movement within the
document.body
)In this case, we are monitoring cursor movement across the entire page just once. We no longer track it for each container because it’s not necessary. There’s no need to monitor the body scrolling here because we are tracking cursor movement throughout the entire body, so its position determination already includes it.
Instead of adding a new div on top of the text, use a pseudo-class and add a circular radiant with a big hole in the middle. When moving the cursor over the box, update the CSS variables that control the
background-position
of the pseudo-element.[edit]
I also made the image into a pseudo-element to remove some javascript code.
getBoundingClientRect
is compute-heavy so I moved it outside. This means that the javascript code must run after the first paint of the HTML code.Finally, it’s not proper to hard code pixels like I did, but you can probably use the
rect
variable now when it’s outside themousemove
event.Of course you can make it better from now on according to your needs.
It is hard to understand what you are trying to achieve… As an option, you can use
box-shadow
.Something like this: