Reputation: 317
Info in advance:
You can see the current code or the live demo (without the working hover image) at https://juek3y.com.
The idea:
I want, when I hover with my cursor (a black circle) over the image, to get displayed only exactly this part of the image (and not the whole image), over which the cursor is hovering.
The problem:
Where do I start? I have seen a few CodePens that work with Z-Index. However, I have not been successful with them so far. Also a sample website that has something like this would be enough for me.
For a better understanding I have two more example pictures.
In the first image, the smaller circle / cursor (black / turquoise circle) hovers over the round text, but it does not yet intersect the image. Therefore this is hidden.
In the second image, the cursor is already hovering a bit above the image, this part of the image is also shown.
Upvotes: 0
Views: 3122
Reputation: 36574
You can use CSS mask to 'cut a hole' in an element.
You can put the image that is to be (partially) revealed as background to a div, then overlay that with an after pseudo-element which has as background the image you want at the front, masked with a radial gradient which gets positioned with the mouse position.
This snippet overlays a colored image with a grayscale one as an example:
window.onload = function() {
const div = document.querySelector('.hole');
let isIn = false;
div.addEventListener('mouseover', function() {
isIn = true;
});
div.addEventListener('mouseout', function() {
isIn = false;
});
div.addEventListener('mousemove', function() {
if (isIn) {
div.style.setProperty('--x', event.clientX + 'px');
div.style.setProperty('--y', event.clientY + 'px');
}
});
}
.hole {
background-image: url(https://picsum.photos/id/1016/1024/768);
background-size: cover;
--x: 200px;
--y: 150px;
width: 100vw;
height: 100vh;
position: relative;
}
.hole::after {
content: '';
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-image: url(https://picsum.photos/id/1016/1024/768?grayscale);
background-size: cover;
z-index: 1;
-webkit-mask-repeat: no-repeat no-repeat;
mask-repeat: no-repeat no-repeat;
-webkit-mask-image: radial-gradient(200px at var(--x) var(--y), transparent 95%, black 100%);
mask-image: radial-gradient(200px at var(--x) var(--y), transparent 95%, black 100%);
}
<div class="hole"></div>
Upvotes: 2
Reputation: 12918
You can use the CSS clip-path
property in conjunction with a mousemove
listener to show the front image under the mouse, and clearing the clip-path on mouseleave
.
Rough working snippet using a CSS invert filter on the overlay image. You could easily add event delegation for handling multiple overlays etc.
const overlay = document.querySelector('.overlay');
overlay.addEventListener('mousemove', e => {
const {height, width} = e.currentTarget.getBoundingClientRect();
const x = e.offsetX;
const y = e.offsetY;
const xPercent = Math.round((x/width)*100);
const yPercent = Math.round((y/height)*100);
e.currentTarget.style.clipPath = `circle(18% at ${xPercent}% ${yPercent}%)`;
});
overlay.addEventListener('mouseleave', e => {
e.currentTarget.style.clipPath = null;
});
.container {
position: relative;
}
.container img {
width: 200px;
height: 200px;
position: absolute;
top: 0;
left: 0;
}
.overlay {
filter: invert(var(--value, 100%));
clip-path: circle(0 at 49% 45%);
}
<div class='container'>
<img src='https://source.unsplash.com/random' />
<img src='https://source.unsplash.com/random' class='overlay'/>
</div>
Upvotes: 1