인터랙션

포인터 따라 기울어지는 3D 틸트 카드

마우스 위치를 perspective 회전으로 변환하고, 광택과 시차 깊이감까지 더한 awwwards풍 카드 인터랙션.

ReactTypeScriptCSS 3D TransformsPointer Eventsperspective
라이브 데모
새 탭에서 열기
데모 불러오는 중…

제작 과정

한 줄 요약

포인터 위치를 perspective 회전으로 바꿔 카드가 마우스를 따라 기울어지는 3D 인터랙션. 광택(glare)과 translateZ 시차 깊이감까지 더해 "살아있는" 카드를 만든다.

이럴 때 필요해요

제품 카드·포트폴리오 썸네일이 밋밋해서 시선을 못 끌 때. 정적인 그리드에 hover 디테일 하나만 얹어도 "공들인 사이트"라는 인상이 확 산다.

vanilla-tilt 같은 라이브러리도 있지만 핵심 로직은 30줄이면 끝나고, 직접 짜야 perspective 거리·기울기 한계·시차 깊이를 디자인에 맞춰 미세 조정할 수 있다.

어떻게 동작하나

  1. 카드 위 포인터 위치를 카드 크기로 나눠 0~1 비율로 측정한다.
  2. 그 비율을 rotateX·rotateY 각도로 변환한다 — 중심(0.5)에서 멀수록 크게, 세로축은 부호를 뒤집어 자연스러운 방향으로.
  3. perspective()를 포함한 transform을 카드에 적용하고, 같은 좌표에 radial-gradient 광택 오버레이를 둔다.
  4. 카드 안쪽 요소엔 translateZ를 단계별로 줘서, 기울 때 앞 요소가 더 튀어나오는 시차(parallax)를 만든다.

놓치기 쉬운 것

  • hover는 초당 수십 번 발생하는 핫패스다. setState로 처리하면 매 프레임 리렌더가 쌓이니, useRef로 DOM style을 직접 갱신해 리렌더를 0으로 만든다. 부드러움은 CSS transition이 담당.
  • 부모에 transform-style: preserve-3d가 없으면 자식의 translateZ가 평면으로 뭉개진다.
  • 모바일에서 touch-action: none을 안 주면 카드 위 드래그를 페이지 스크롤이 가져간다.
  • transition을 transform에 0.2s 이상 길게 주면 포인터를 못 따라와 끈적해 보인다 — 0.15s 안쪽.

이런 곳에 써요

  • 포트폴리오·제품 그리드의 썸네일 카드
  • 가격표·기능 소개 섹션에서 마우스 유도용 hover 디테일

소스 코드

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

export const metadata: Metadata = {
  title: "3D 틸트 카드 (데모)",
  description:
    "마우스 위치에 따라 perspective로 기울어지는 3D 카드. glare 하이라이트 + translateZ 시차 깊이감.",
  robots: { index: false, follow: false },
};

export default function Page() {
  return (
    <main className="flex min-h-[100dvh] items-center justify-center bg-slate-50">
      <TiltCardDemo />
    </main>
  );
}
63조회수

댓글