Перейти к содержимому

Custom Hover Cursor

/components/ui/CustomCursor.tsx
'use client'
import React, { useEffect, useState } from 'react'
const CustomCursor: React.FC = () => {
const [cursorPosition, setCursorPosition] = useState({ top: 0, left: 0 })
const [isHovering, setIsHovering] = useState(false)
useEffect(() => {
const cursor = document.querySelector('.custom-cursor') as HTMLElement
const hoverElements = document.querySelectorAll('.hover-cursor')
if (cursor) {
const handleMouseMove = (e: MouseEvent) => {
setCursorPosition({ top: e.clientY, left: e.clientX })
}
const handleMouseEnter = () => {
setIsHovering(true)
}
const handleMouseLeave = () => {
setIsHovering(false)
}
document.addEventListener('mousemove', handleMouseMove)
hoverElements.forEach((element) => {
element.addEventListener('mouseenter', handleMouseEnter)
element.addEventListener('mouseleave', handleMouseLeave)
})
return () => {
document.removeEventListener('mousemove', handleMouseMove)
hoverElements.forEach((element) => {
element.removeEventListener('mouseenter', handleMouseEnter)
element.removeEventListener('mouseleave', handleMouseLeave)
})
}
} else {
console.error('Cursor element not found!')
}
}, [])
return (
<div
className={`custom-cursor ${isHovering ? 'cursor-hover' : ''}`}
style={{
top: `${cursorPosition.top}px`,
left: `${cursorPosition.left}px`,
}}>
<span className="cursor-text">
<svg
className="stroke-1"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round">
<path d="M7 7h10v10" />
<path d="M7 17 17 7" />
</svg>
</span>
</div>
)
}
export default CustomCursor
/app/page.tsx
import React from 'react'
import CustomCursor from '../components/CustomCursor'
const HomePage: React.FC = () => {
return (
<div>
<CustomCursor />
<div className="hover-cursor">Hover over me!</div>
<div className="hover-cursor">Another hover element</div>
{/* Другие элементы */}
</div>
)
}
export default HomePage
/styles/globals.css
.custom-cursor {
position: fixed;
width: 30px;
height: 30px;
border-radius: 50%;
background-color: rgba(209, 203, 191, 0.55);
border: 1px solid rgba(255, 255, 255, 0.07);
backdrop-filter: blur(10px);
pointer-events: none;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease, width 0.3s, height 0.3s, background-color 0.3s;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
line-height: 22px;
font-size: 16px;
opacity: 0;
/* Начальное состояние (скрыто) */
}
.hover-cursor {
cursor: none !important;
/* Убираем системный курсор при наведении */
}
.cursor-hover {
opacity: 1;
/* Плавно появляется */
width: 96px;
height: 96px;
background-color: rgba(209, 203, 191, 0.55);
border: 1px solid rgba(255, 255, 255, 0.07);
}
.custom-cursor svg {
width: 12px;
/* Исходный маленький размер */
height: 12px;
transition: transform 0.3s ease;
/* Плавный переход для иконки */
}
.cursor-hover svg {
transform: scale(6);
/* Увеличить иконку */
}