Hi this is a bit of an odd question, I've seen similar effects to whats I'm going for but not exactly the same not sure if what I want to do is possible. I want to have two divs stacked with the contents of the div below revealed only in a specific area (around the cursor), is there a way to make only part of a div transparent? Or is there any other way to achieve this effect?
1 Answer
Instead of having the element you want to show in the background you can put it in front and only show part of it via a clip-path;
For the coordinates I use CSS variables though you could also overwrite the style directly.
// Get element from the DOM const container = document.querySelector('.container'); // Apply event listener container.addEventListener('mousemove', updateCoords, false); function updateCoords(event) { // Get X and Y coordinates const { offsetX, offsetY } = event; // Update coordinates container.style.setProperty('--x', offsetX + 'px'); container.style.setProperty('--y', offsetY + 'px'); } .container { border: 1px solid #000; width: 300px; height: 300px; } /* Show child when hovering the container */ .container:hover .child { display: block; } .child { clip-path: ellipse(30px 30px at var(--x) var(--y)); display: none; } <div class="container"> <img class="child" src="//picsum.photos/300" width="300" height="300" /> </div> You can use requestAnimationFrame to make the circle move more smoothly
// Get element from the DOM const container = document.querySelector('.container'); // Apply event listener container.addEventListener('mousemove', updateCoords, false); function updateCoords(event) { // Get X and Y coordinates const { offsetX, offsetY } = event; // Update coordinates requestAnimationFrame(() => { container.style.setProperty('--x', offsetX + 'px'); container.style.setProperty('--y', offsetY + 'px'); }); } .container { border: 1px solid #000; width: 300px; height: 300px; } /* Show child when hovering the container */ .container:hover .child { display: block; } .child { clip-path: ellipse(30px 30px at var(--x) var(--y)); display: none; } <div class="container"> <img class="child" src="//picsum.photos/300" width="300" height="300" /> </div> Example with text
// Get element from the DOM const container = document.querySelector('.container'); // Apply event listener container.addEventListener('mousemove', updateCoords, false); function updateCoords(event) { // Get X and Y coordinates const {offsetX, offsetY} = event; // Update coordinates requestAnimationFrame(() => { container.style.setProperty('--x', offsetX + 'px'); container.style.setProperty('--y', offsetY + 'px'); }); } .container { min-height: 100vh; min-width: 100vh; overflow: hidden; } .container:hover .code { display: flex; } .display, .code { position: absolute; display: flex; align-items: center; justify-content: center; width: 100vw; height: 100vh; background-color: rgb(49, 49, 49); color: rgb(240, 191, 29); pointer-events: none; } .code { clip-path: ellipse(100px 100px at var(--x) var(--y)); display: none; background-color: rgb(3, 3, 3); color: rgb(101, 253, 101); } <div class="container"> <div class="display"> <h1>Header</h1> </div> <div class="code"> <h3><h1>Header</h1></h3> </div> </div> 3 Comments
jacquesrockell
Hi thanks this is almost exactly what I was after, I'm using this effect to show text not images and it works perfectly until the mouse goes over the text, it sends the circle to the top of the screen, I'm sorta stumped on why this may be happening any ideas?
StackByMe
@jacquesrockell yes this is because the event bubbles. Meaning once you hover the text it will read coordinates from the heading not the container. One easy solution is to add
pointer-events: none; to your content. See update snippet.jacquesrockell
The effect is working great, ty

<canvas>in some way. This being said, this question is off-topic for Stackoverflow :)