返回组件库

悬浮卡片

复刻来源unseen.co
React · Vue3卡片变换ReactVue3指针交互

指针在卡片内移动时轻微 3D 倾斜,静止时保持缓慢浮动。

业务项目无源码 → 我们复刻实现,自动适配 React,复制代码拿去即可使用。

演示预览实时时长 1x
3D Tilt Card

自适应物理倾斜卡片

根据鼠标光标与陀螺仪向量,自适应产生平滑物理透视与反光高光跟随。

Raycast · 物理微动效进入卡片
播放速度已适配 prefers-reduced-motion
TiltCard.jsx
/**
 * OmniMotion — 悬浮卡片 / TiltCard (React 18+ · 指针跟随倾斜)
 * 复刻来源: unseen.co — 指针在卡片内移动时轻微 3D 倾斜
 * 用法: <TiltCard tilt range={2}>...</TiltCard>
 */
import { useRef } from "react";

export default function TiltCard({ tilt = true, range = 2, children }) {
  const ref = useRef(null);

  function onMove(event) {
    if (!tilt || !ref.current) return;
    const rect = ref.current.getBoundingClientRect();
    const x = (event.clientX - rect.left) / rect.width - 0.5;
    const y = (event.clientY - rect.top) / rect.height - 0.5;
    ref.current.style.transform =
      "perspective(600px) rotateY(" + x * range * 2 + "deg) rotateX(" + -y * range * 2 + "deg)";
  }

  function onLeave() {
    if (ref.current) ref.current.style.transform = "";
  }

  return (
    <div ref={ref} className="mk-tilt" onMouseMove={onMove} onMouseLeave={onLeave}>
      {children}
    </div>
  );
}

/* 样式(可直接放入全局 CSS)
.mk-tilt {
  display: flex; flex-direction: column; gap: 8px; width: 118px;
  padding: 14px 14px 16px; border-radius: 8px;
  background: var(--mk-stage-surface); border: 1px solid var(--mk-stage-line);
  transition: transform 240ms cubic-bezier(0.2, 0.8, 0.2, 1);
  animation: mk-tilt 4s cubic-bezier(0.3, 0, 0, 1) infinite;
}
@keyframes mk-tilt {
  0%, 100% { transform: translateY(-6px) rotate(-2deg); }
  50% { transform: translateY(6px) rotate(2deg); }
}
@media (prefers-reduced-motion: reduce) { .mk-tilt { animation: none } }
*/
属性 · Props
属性类型默认值说明
tiltbooleantrue是否开启指针跟随倾斜
rangenumber2最大倾斜角度(deg)
<Card interactive tilt range={2} />