I want to create a fancy hero section for my company. I'm using clip-path and some JS to achieve a paint spray effect on mouse move, and it works perfectly in the VCS preview. However, when I try it in web browsers like Chrome, Mozilla, or Edge, it doesn't work. It seems like the cursor's position can't be found properly. The clip-path shows in random places and for a few seconds or doesn't show at all. What's more? if its i left corner without margin: auto; it's work great but it had to be center.
Page where i want to use it: https://hoffmannteile.de/ Here's the code I'm using (it has to be in one file because it's a closed CMS):
document.addEventListener('DOMContentLoaded', function () {
const cars = document.querySelectorAll('.car');
cars.forEach(car => {
car.addEventListener('mousemove', function (e) {
const x = e.pageX - car.offsetLeft;
const y = e.pageY - car.offsetTop;
car.style.setProperty('--x', x + 'px');
car.style.setProperty('--y', y + 'px');
});
});
});
.paint {
max-height: 338px;
max-width: 600px;
margin: auto;
}
.malowanie {
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.cont {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.cont .car {
position: relative;
height: 338px;
width: 600px;
background-image: url('https://composer.idosell.com/gfx/30226/SprinterWhite.png');
background-size: cover;
display: flex;
justify-content: center;
align-items: center;
}
.cont .car::before {
content: '';
position: absolute;
z-index: 1;
}
.cont .car::after {
content: '';
position: absolute;
inset: 0;
background: var(--img);
background-size: cover;
clip-path: circle(0px at 0 0);
z-index: 2;
transition: clip-path 0.15s;
}
.cont .car:hover::after {
clip-path: circle(100px at var(--x) var(--y));
cursor: url('https://composer.idosell.com/gfx/30226/paint-spray-icon.svg'), auto;
}
<section class="paint">
<div class="malowanie">
<div class="cont">
<div class="car" style="--img: url('https://composer.idosell.com/gfx/30226/SprinterRedHof.png')"></div>
</div>
</div>
</section>
Use mouse coordinate relative to the clientX/Y
and use Element.getBoundingClientRect() left
and top
values
document.addEventListener('DOMContentLoaded', function() {
const cars = document.querySelectorAll('.car');
cars.forEach(car => {
car.addEventListener('mousemove', function(e) {
const bcr = car.getBoundingClientRect();
const x = e.clientX - bcr.left;
const y = e.clientY - bcr.top;
car.style.setProperty('--x', x + 'px');
car.style.setProperty('--y', y + 'px');
});
});
});
body {
min-height: 300px; /* just to test scroll */
}
.paint {
max-height: 338px;
max-width: 600px;
margin: auto;
}
.malowanie {
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.cont {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.cont .car {
position: relative;
height: 338px;
width: 600px;
background-image: url('https://composer.idosell.com/gfx/30226/SprinterWhite.png');
background-size: cover;
display: flex;
justify-content: center;
align-items: center;
}
.cont .car::before {
content: '';
position: absolute;
z-index: 1;
}
.cont .car::after {
content: '';
position: absolute;
inset: 0;
background: var(--img);
background-size: cover;
clip-path: circle(0px at 0 0);
z-index: 2;
transition: clip-path 0.15s;
}
.cont .car:hover::after {
clip-path: circle(100px at var(--x) var(--y));
cursor: url('https://composer.idosell.com/gfx/30226/paint-spray-icon.svg'), auto;
}
<h1>Some title to test offset</h1>
<section class="paint">
<div class="malowanie">
<div class="cont">
<div class="car" style="--img: url('https://composer.idosell.com/gfx/30226/SprinterRedHof.png')"></div>
</div>
</div>
</section>