如何在ReactJS中实现GitHub官网风格的悬浮卡片动画?
React实现GitHub式悬浮卡片Blob动画效果
核心技术思路
- 鼠标位置追踪:在卡片元素上监听
mousemove、mouseenter、mouseleave事件,计算鼠标相对于卡片容器的坐标偏移,转化为百分比值驱动动画。 - CSS变量联动:将鼠标位置的百分比值存入CSS变量,通过
transform实现卡片的3D倾斜变形(rotateX/rotateY),同时控制Blob元素的位置偏移。 - Blob形状动态调整:用SVG的
<path>或CSSclip-path定义Blob形状,通过鼠标位置动态修改路径参数实现跟随变形;也可使用圆角div配合缩放/位移模拟基础Blob效果。 - 平滑过渡:给卡片和Blob元素添加
transition或使用动画库的弹簧物理效果,让动画更自然流畅。
原生React实现代码示例
以下是无依赖的基础实现,包含卡片变形和Blob跟随效果:
import { useState, useEffect, useRef } from 'react'; const HoverCard = ({ children }) => { const cardRef = useRef(null); const [mousePos, setMousePos] = useState({ x: 0, y: 0 }); const [isHovered, setIsHovered] = useState(false); const handleMouseMove = (e) => { if (!cardRef.current) return; const rect = cardRef.current.getBoundingClientRect(); // 计算鼠标在卡片内的百分比位置(中心为原点) const x = ((e.clientX - rect.left) / rect.width - 0.5) * 100; const y = ((e.clientY - rect.top) / rect.height - 0.5) * 100; setMousePos({ x, y }); }; useEffect(() => { const card = cardRef.current; if (!card) return; card.addEventListener('mousemove', handleMouseMove); card.addEventListener('mouseenter', () => setIsHovered(true)); card.addEventListener('mouseleave', () => { setIsHovered(false); setMousePos({ x: 0, y: 0 }); }); return () => { card.removeEventListener('mousemove', handleMouseMove); card.removeEventListener('mouseenter', () => setIsHovered(true)); card.removeEventListener('mouseleave', () => setIsHovered(false)); }; }, []); return ( <div ref={cardRef} className="hover-card" style={{ '--mouse-x': `${mousePos.x}%`, '--mouse-y': `${mousePos.y}%`, '--hover': isHovered ? 1 : 0, }} > {/* Blob背景元素 */} <div className="card-blob" /> {/* 卡片内容 */} <div className="card-content">{children}</div> </div> ); }; export default HoverCard;
对应的CSS样式:
.hover-card { position: relative; width: 300px; height: 200px; padding: 2rem; border-radius: 16px; overflow: hidden; background: #fff; box-shadow: 0 4px 20px rgba(0,0,0,0.1); transition: transform 0.2s ease; transform: perspective(1000px) rotateX(calc(var(--mouse-y, 0) * -0.5deg)) rotateY(calc(var(--mouse-x, 0) * 0.5deg)); } .card-blob { position: absolute; top: 50%; left: 50%; width: 150px; height: 150px; border-radius: 45% 55% 70% 30% / 40% 50% 50% 60%; background: #2ea44f; transform: translate( calc(var(--mouse-x, 0) * -0.3%), calc(var(--mouse-y, 0) * -0.3%) ) scale(calc(1 + var(--hover, 0) * 0.1)); opacity: calc(0.3 + var(--hover, 0) * 0.2); transition: all 0.3s ease; z-index: 0; } .card-content { position: relative; z-index: 1; }
推荐实用库
如果需要更复杂的动画效果或简化开发流程,可使用以下库:
- Framer Motion:通过
motion组件和useMotionValue轻松实现鼠标跟随的弹簧动画,支持自定义Blob路径的动态修改,API简洁易上手。 - React Spring:基于物理弹簧的动画库,适合模拟自然的跟随和变形效果,能精准控制动画的阻尼、刚度等参数。
- GSAP:功能强大的动画引擎,可处理复杂的SVG路径变形和3D变换,适合对动画精度要求极高的场景。
内容的提问来源于stack exchange,提问作者Sajjad Javadi
相关产品推荐
相关产品推荐

