本页出处
设计风格资料库
内容来自 luckymaomi 的 UI 风格库(复刻版),以 MIT 许可 提供。本站镜像收录,仅作学习参考;这一页的原始地址是 原站页面。
← 回到导览访问原站仓库
返回动效库
指针进阶

3D 透视倾斜

鼠标在卡片上移动时,卡片随鼠标位置产生 3D 透视倾斜效果,营造沉浸式的空间深度感。

悬停时continuous

交互预览

动效定义与代码

{
  "slug": "tilt-3d",
  "name": "3D 透视倾斜",
  "nameEn": "3D Tilt",
  "description": "鼠标在卡片上移动时,卡片随鼠标位置产生 3D 透视倾斜效果,营造沉浸式的空间深度感。",
  "descriptionEn": "Card tilts in 3D space following cursor position, creating an immersive depth effect with perspective transforms.",
  "category": "hover",
  "tags": [
    "3d",
    "perspective",
    "tilt",
    "hover",
    "mouse-tracking",
    "interactive"
  ],
  "trigger": "on-hover",
  "difficulty": "intermediate",
  "duration": "continuous",
  "easing": "ease-out",
  "cssProperties": [
    "transform",
    "perspective"
  ],
  "isGPUAccelerated": true,
  "previewBg": "dark",
  "keywords": [
    "3d tilt",
    "perspective",
    "mouse tracking",
    "card hover",
    "parallax card",
    "depth"
  ],
  "useCases": [
    "Product showcase cards",
    "Pricing cards",
    "Portfolio project cards",
    "Image gallery thumbnails"
  ],
  "relatedAnimations": [
    "hover-lift",
    "spotlight-card",
    "magnetic-hover"
  ],
  "recommendedStyles": [
    "glassmorphism",
    "dark-mode",
    "cyberpunk-neon",
    "apple-style"
  ],
  "codeSnippets": [
    {
      "label": "CSS Keyframes",
      "language": "css",
      "code": "/* 3D Tilt requires JS for mouse tracking.\n   CSS sets up the perspective container and smooth transitions. */\n\n.tilt-container {\n  perspective: 1000px;\n}\n\n.tilt-card {\n  transform-style: preserve-3d;\n  transition: transform 150ms ease-out;\n  will-change: transform;\n}\n\n.tilt-card:hover {\n  /* JS overrides this with dynamic rotateX/rotateY values */\n  transform: rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) scale3d(1.02, 1.02, 1.02);\n}\n\n.tilt-card .tilt-shine {\n  position: absolute;\n  inset: 0;\n  background: radial-gradient(\n    circle at var(--mouse-x, 50%) var(--mouse-y, 50%),\n    rgba(255, 255, 255, 0.15),\n    transparent 60%\n  );\n  pointer-events: none;\n  opacity: 0;\n  transition: opacity 150ms ease-out;\n}\n\n.tilt-card:hover .tilt-shine {\n  opacity: 1;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .tilt-card {\n    transition: none;\n    transform: none !important;\n  }\n  .tilt-card .tilt-shine {\n    display: none;\n  }\n}"
    },
    {
      "label": "Tailwind CSS",
      "language": "css",
      "code": "/* Tailwind v4 — 3D Tilt container and card */\n\n@utility perspective-1000 {\n  perspective: 1000px;\n}\n\n@utility preserve-3d {\n  transform-style: preserve-3d;\n}\n\n/* Usage:\n  <div class=\"perspective-1000\">\n    <div class=\"preserve-3d transition-transform duration-150 ease-out hover:scale-[1.02]\"\n         style=\"transform: rotateX(var(--tilt-x)) rotateY(var(--tilt-y))\">\n      Card content\n    </div>\n  </div>\n*/"
    },
    {
      "label": "Framer Motion",
      "language": "tsx",
      "code": "\"use client\";\n\nimport { motion, useMotionValue, useSpring } from \"framer-motion\";\nimport { type MouseEvent, type ReactNode } from \"react\";\n\ninterface Tilt3DProps {\n  children: ReactNode;\n  maxTilt?: number;\n  className?: string;\n}\n\nexport function Tilt3D({ children, maxTilt = 15, className }: Tilt3DProps) {\n  const rotateX = useMotionValue(0);\n  const rotateY = useMotionValue(0);\n  const springX = useSpring(rotateX, { stiffness: 300, damping: 20 });\n  const springY = useSpring(rotateY, { stiffness: 300, damping: 20 });\n\n  function handleMouseMove(e: MouseEvent<HTMLDivElement>) {\n    const rect = e.currentTarget.getBoundingClientRect();\n    const x = (e.clientX - rect.left) / rect.width - 0.5;\n    const y = (e.clientY - rect.top) / rect.height - 0.5;\n    rotateX.set(-y * maxTilt);\n    rotateY.set(x * maxTilt);\n  }\n\n  function handleMouseLeave() {\n    rotateX.set(0);\n    rotateY.set(0);\n  }\n\n  return (\n    <div style={{ perspective: 1000 }}>\n      <motion.div\n        className={className}\n        onMouseMove={handleMouseMove}\n        onMouseLeave={handleMouseLeave}\n        style={{\n          rotateX: springX,\n          rotateY: springY,\n          transformStyle: \"preserve-3d\",\n        }}\n      >\n        {children}\n      </motion.div>\n    </div>\n  );\n}"
    }
  ]
}