April 13, 2021
awdagency.com 사이트에서 커서 모션 애니메이션이 눈에 띄어 따라 만들어봤습니다.
커스텀 마우스 커서를 만들기 위해서 먼저 css 로 가려줍니다.
html {
cursor: none;
}
그다음 커스텀 마우스 커서를 지정할 태그를 생성합니다. 주된 커스텀 마우스 커서 외에 뒤에서 따라다니는 원은 부드러운 모션을 주기 위해 따로 빼둡니다.
<body>
<div class="cursor-wrapper">
<!-- 마우스 위치를 감지하고 위치를 변경하기 위한 wrapper -->
<div class="custom-cursor"></div>
<!--마우스 커서 모양 -->
<div class="cursor-text">DISCOVER</div>
<!-- 커서가 이미지 위에서 있을 때 표시해줄 텍스트-->
</div>
<!-- 마우스 커서보다 한 템포 느리게 뒤따라 오는 꼬리-->
<div class="cursor-tail"></div>
</body>
커스텀 마우스 커서의 position
을 absolute
로 지정합니다. top
과 left
값을 건드려 움직여줄 겁니다.
.cursor-wrapper {
position: absolute;
top: 0;
left: 0;
width: 25px;
height: 25px;
border-radius: 50%;
}
커스텀 커서 클래스를 만듭니다.
class CustomCursor {
constructor({ $target }) {
this._$target = $target // custom cursor wrapper 태그
this._radius = $target.clientHeight / 2 // 반지름
this._pos = {
x: null,
y: null,
} // 마우스 위치
}
// 변경된 마우스 위치를 전달 받는 접근자 프로퍼티
set pos(newPos) {
this._pos = newPos
// 정확히 마우스 위치가 중앙으로 오도록 반지름을 빼줌
this._$target.style.top = `${newPos.y - this.radius}px`
this._$target.style.left = `${newPos.x - this.radius}px`
}
}
mousemove
이벤트에서 마우스 위치를 가져와 customCursor
의 위치를 동기화합니다.
const customCursor = new CustomCursor({
$target: document.querySelector('.cursor-wrapper'),
})
window.addEventListener('mousemove', e => {
customCursor.pos = { x: e.x, y: e.y }
})
이제 마우스 뒤를 쫒아오는 꼬리를 만져줍니다. 이부분은 마우스 부드럽게 따라오는 이미지 글을 참고했습니다. cursor-tail
의 위치 변경을 mousemove
이벤트 콜백함수에 같이 두지 않은 까닭은 마우스가 멈춰도 끝까지 따라가 마우스가 있는 위치에 정확히 옮겨주기 위함입니다.
const $cursorTail = document.querySelector('.cursor-tail')
function followCursor() {
// 현재 꼬리 위치 가져오기
const tail_x = parseInt($cursorTail.style.left.replace('px', '')) || 0
const tail_y = parseInt($cursorTail.style.top.replace('px', '')) || 0
// 커서와 꼬리 사이의 거리를 나누는 값 (10) 으로 속도 조절을 합니다.
// 나누는 값이 클수록 느려지고 작을수록 빨라집니다
$cursorTail.style.top = `${Math.round(
tail_y + (customCursor.pos.y - tail_y) / 10
)}px`
$cursorTail.style.left = `${Math.round(
tail_x + (customCursor.pos.x - tail_x) / 10
)}px`
requestAnimationFrame(followCursor)
}
requestAnimationFrame(followCursor)
저처럼 수학공식이 이해하기 어려운 분들을 위해서 제가 이해한 데까지 설명하자면 이렇습니다.
꼬리 x축 위치를 곧바로 customerCusor의 x축 위치에 놓게 되면 꼬리와 커서가 동시에 움직이게 되어 원하는 ‘따라가는 모션’을 보여줄 수 없습니다.
$cursorTail.style.left = `${customCursor.pos.x}px`
현재 꼬리의 x축 위치에서 커서와 x축으로 떨어진 거리를 더해줘도 위와 동일한 결과가 나옵니다.
$cursorTail.style.left = `${tail_x + (customCursor.pos.x - tail_x)}px`
// = tail_x - tail_x + customCursor.pos.x
// = 0 + customCursor.pos.x
// = customCursor.pos.x
현재 꼬리의 x축과 커서의 x축 위치의 거리를 일정한 값(여기선 10)으로 나누면 어떻게 될까요? 꼬리의 x축 위치가 이전보다는 곧바로 customerCursor의 x축 위치로 가지 않겠죠?
$cursorTail.style.left = `${Math.round(
tail_x + (customCursor.pos.x - tail_x) / 10
)}px`
tail_x
(꼬리 x축 위치) 가 customCursor.pos.x
(커서 x축 위치) 값에 가까워지면 (customCursor.pos.x - tail_x) / 10
이 0에 수렴되어 $cursorTail.style.left = tail_x
로 정지상태가 됩니다. 즉, 커서 위치에서 멈추게 됩니다.