body {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
min-height: 100vh;
background: #191919;
cursor: url("https://s.electerious.com/images/codepen/cursor.svg") 3 3, auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.wrapper {
display: flex;
align-items: center;
justify-content: center;
margin: 1em 0;
}
.cursor {
display: none;
position: fixed;
top: 0;
left: 0;
width: var(--width);
height: var(--height);
transform: translate(calc(var(--x) - var(--width) / 2), calc(var(--y) - var(--height) / 2));
transition-duration: 0.1s;
transition-timing-function: cubic-bezier(0.25, 0.25, 0.42, 1);
transition-property: width, height, transform;
z-index: 1;
pointer-events: none;
will-change: transform;
}
@media (pointer: fine) {
.cursor {
display: block;
}
}
.cursor::after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: var(--radius);
border: 2px solid #34b288;
opacity: var(--scale);
transform: scale(var(--scale));
transition: 0.3s cubic-bezier(0.25, 0.25, 0.42, 1) opacity, 0.3s cubic-bezier(0.25, 0.25, 0.42, 1) transform, 0.1s cubic-bezier(0.25, 0.25, 0.42, 1) border-radius;
}
body:not(body:hover) .cursor::after {
opacity: 0;
transform: scale(0);
}
.link {
display: flex;
align-items: center;
justify-content: center;
margin: 0 1em;
width: var(--size);
height: var(--size);
background: rgba(255, 255, 255, 0.1);
border-radius: 100%;
}
.button {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border: none;
color: white;
cursor: inherit;
padding: 0.5em 1em;
background: rgba(255, 255, 255, 0.1);
border-radius: 5px;
}
Aller au contenu
const updateProperties = (elem, state) => {
elem.style.setProperty('--x', `${state.x}px`);
elem.style.setProperty('--y', `${state.y}px`);
elem.style.setProperty('--width', `${state.width}px`);
elem.style.setProperty('--height', `${state.height}px`);
elem.style.setProperty('--radius', state.radius);
elem.style.setProperty('--scale', state.scale);
};
document.querySelectorAll('.cursor').forEach(cursor => {
let onElement;
const createState = e => {
const defaultState = {
x: e.clientX,
y: e.clientY,
width: 42,
height: 42,
radius: '100px' };
const computedState = {};
if (onElement != null) {
const { top, left, width, height } = onElement.getBoundingClientRect();
const radius = window.getComputedStyle(onElement).borderTopLeftRadius;
computedState.x = left + width / 2;
computedState.y = top + height / 2;
computedState.width = width;
computedState.height = height;
computedState.radius = radius;
}
return {
...defaultState,
...computedState };
};
document.addEventListener('mousemove', e => {
const state = createState(e);
updateProperties(cursor, state);
});
document.querySelectorAll('a, button').forEach(elem => {
elem.addEventListener('mouseenter', () => onElement = elem);
elem.addEventListener('mouseleave', () => onElement = undefined);
});
});