JSFiddle - React, Tailwind, and code Playground
HTML
<div id="text"></div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nam rerum omnis, sunt, fugit optio, mollitia eos explicabo ex modi exercitationem iste earum! Quisquam ex ut, velit dolores culpa omnis sunt!</p>
<img src="https://bipbap.ru/wp-content/uploads/2017/04/priroda_kartinki_foto_03.jpg" data-text="подпись 1" class="image">
<img src="https://st4.depositphotos.com/2012555/37952/i/1600/depositphotos_379525432-stock-photo-vintage-photo-butterfly-tree-flowers.jpg" data-text="подпись 2" class="image">
<ul>
<li class="image">11111</li>
<li class="image">222</li>
</ul>
<div class="circle-cursor circle-cursor--inner"></div>
<div class="circle-cursor circle-cursor--outer"></div>
CSS
html {
cursor: none;
}
body {
margin: 0;
--cursor-color: #000;
}
.circle-cursor {
position: fixed;
left: 0;
top: 0;
pointer-events: none;
border-radius: 50%;
transition: background-color 100ms;
}
.circle-cursor--inner {
width: 5px;
height: 5px;
left: -2.5px;
top: -2.5px;
z-index: 11000;
background-color: var(--cursor-color);
}
.circle-cursor--inner.circle-cursor--hover {
background-color: rgba(0,0,0,0);
}
.circle-cursor--outer {
width: 30px;
height: 30px;
left: -15px;
top: -15px;
border: 1px solid var(--cursor-color);
z-index: 12000;
opacity: 0.2;
}
.circle-cursor--outer.circle-cursor--hover {
background-color: var(--cursor-color);
}
img {
max-width: 300px;
margin-bottom: 55px;
}
li {
margin-bottom: 20px;
}
#text {
position: fixed;
top: -9px;
left: 0px;
transition: opacity 0.3s;
pointer-events: none;
}
JavaScript
const text = document.getElementById("text");
const cursorInner = document.querySelector('.circle-cursor--inner');
const cursorOuter = document.querySelector('.circle-cursor--outer');
let mx = window.innerWidth / 2;
let my = window.innerHeight / 2;
let cxi = mx,
cyi = my,
cxo = mx,
cyo = my;
window.addEventListener('mousemove', (event) => {
mx = event.clientX;
my = event.clientY;
});
function update() {
const dxi = (mx - cxi) * 0.2;
const dyi = (my - cyi) * 0.2;
cxi += dxi;
cyi += dyi;
const dxo = (mx - cxo) * 0.07;
const dyo = (my - cyo) * 0.07;
cxo += dxo;
cyo += dyo;
cursorOuter.style.transform = `translate(${cxo}px, ${cyo}px)`;
cursorInner.style.transform = `translate(${cxi}px, ${cyi}px)`;
text.style.transform = `translate(${cxo}px, ${cyo}px)`;
requestAnimationFrame(update);
}
requestAnimationFrame(update);
document.body.addEventListener('mouseover', (event) => {
const image = event.target.closest('.image');
if (!image) return;
text.textContent = image.dataset.text;
text.style.opacity = 1;
cursorInner.classList.add('circle-cursor--hover');
cursorOuter.classList.add('circle-cursor--hover');
});
document.body.addEventListener('mouseout', (event) => {
const image = event.target.closest('.image');
if (!image) return;
text.style.opacity = 0;
cursorInner.classList.remove('circle-cursor--hover');
cursorOuter.classList.remove('circle-cursor--hover');
});