인터랙션

Magnetic Button 커서 자력 효과 CTA

마우스 위치를 추적해 lerp 보간으로 부드럽게 끌려오는 버튼. CTA 임팩트 + 인터랙션 디테일을 동시에 보여주는 패턴입니다.

ReactTypeScriptrequestAnimationFramePointer Events
라이브 데모
새 탭에서 열기
데모 불러오는 중…

제작 과정

CTA 버튼은 사이트의 컨버전 시작점. 작은 디테일 하나가 눌러보고 싶은 마음을 만든다.

Awwwards / Site of the Day 류 사이트의 단골 효과 - 흔하지만 만들어 본 사람은 의외로 적다.

구현 포인트

- 핵심 알고리즘 3단계:

a. mousemove에서 요소 중심 좌표 vs 마우스 좌표의 거리를 계산

b. 활성 반경 안일 때만 target 위치 갱신 + 거리 기반 falloff (1 - dist/radius) 적용 - 멀어질수록 영향이 줄어들어야 자연스러움

c. requestAnimationFrame 안에서 current += (target - current) * lerp - 매 프레임 선형 보간

- setState가 아니라 직접 el.style.transform = translate3d(...) - 매 프레임 React 리렌더 폭증 방지

- translate3d로 GPU layer 승격, 60fps 유지

- 강도(strength) 0.18 / 0.42 / 0.7 세 가지 시연 - 각각의 느낌 차이를 한눈에

알아둘 점

- mousemove를 버튼 자체가 아니라 document에 붙임. 버튼 자체에 붙이면 빠른 진입 시 첫 이벤트를 놓침

- cleanup에서 el.style.transform = "" 비워주기 - strict mode 더블 마운트나 unmount 후 잔여 스타일 방지

- 모바일/터치엔 동작 안 함 (mouse 인터랙션이라). PC 한정 디테일 - 모바일은 그냥 일반 버튼

- 접근성 영향 없음 - hit area는 transform 적용 후에도 동일. 키보드 사용자에는 그저 평범한 버튼

- strength는 0.4 정도가 자연스러움. 0.7 이상은 장난감 같은 인상 - 브랜드 톤에 맞게

실무 활용 예시

- 메인 페이지 hero CTA ("시작하기" 등)

- 포트폴리오 사이트의 "프로젝트 보기" 같은 강조 버튼

- 인터랙션 어워드 응모용 사이트의 디테일 포인트

소스 코드

· 데모 페이지에서 자동 추출
import type { Metadata } from "next";
import { MagneticButtonDemo } from "./-components/MagneticButtonDemo";

export const metadata: Metadata = {
  title: "Magnetic Button — 커서 자력 버튼 (데모)",
  description:
    "마우스 위치를 추적해 lerp 보간으로 부드럽게 끌려오는 magnetic 버튼 효과. CTA 임팩트용 인터랙션.",
  robots: { index: false, follow: false },
};

export default function Page() {
  return <MagneticButtonDemo />;
}
74조회수

댓글