聚光灯卡片
鼠标在卡片上方移动时,呈现手电筒照亮卡片局部的光影跟随效果。
交互预览
动效定义与代码
{
"slug": "spotlight-card",
"name": "聚光灯卡片",
"nameEn": "Spotlight Card",
"description": "鼠标在卡片上方移动时,呈现手电筒照亮卡片局部的光影跟随效果。",
"descriptionEn": "A flashlight-like spotlight follows the cursor when hovering over the card.",
"category": "micro-interaction",
"tags": [
"hover",
"spotlight",
"glow",
"mouse-tracking"
],
"trigger": "on-hover",
"difficulty": "advanced",
"duration": "continuous",
"easing": "linear",
"cssProperties": [
"background-image"
],
"isGPUAccelerated": true,
"previewBg": "dark",
"keywords": [
"spotlight",
"mouse tracking",
"glow",
"card effect",
"lighting"
],
"useCases": [
"Pricing feature cards",
"Bento grid items",
"Portfolio project showcase"
],
"relatedAnimations": [
"hover-glow"
],
"recommendedStyles": [
"glassmorphism",
"dark-mode",
"modern-gradient"
],
"codeSnippets": [
{
"label": "Tailwind CSS + React",
"language": "tsx",
"code": "import { useRef, useState } from \"react\";\n\nexport function SpotlightCard({ children }: { children: React.ReactNode }) {\n const divRef = useRef<HTMLDivElement>(null);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [opacity, setOpacity] = useState(0);\n\n const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n if (!divRef.current) return;\n const rect = divRef.current.getBoundingClientRect();\n setPosition({ x: e.clientX - rect.left, y: e.clientY - rect.top });\n };\n\n return (\n <div\n ref={divRef}\n onMouseMove={handleMouseMove}\n onMouseEnter={() => setOpacity(1)}\n onMouseLeave={() => setOpacity(0)}\n className=\"relative overflow-hidden border border-white/10 bg-black/20 p-8\"\n >\n <div\n className=\"pointer-events-none absolute -inset-px transition-opacity duration-300\"\n style={{\n opacity,\n background: `radial-gradient(600px circle at ${position.x}px ${position.y}px, rgba(255,255,255,0.1), transparent 40%)`,\n }}\n />\n <div className=\"relative z-10\">{children}</div>\n </div>\n );\n}"
},
{
"label": "Framer Motion",
"language": "tsx",
"code": "import { useRef } from \"react\";\nimport { motion, useMotionValue, useSpring } from \"framer-motion\";\n\n// Tip: consider disabling for reduced motion users\n// import { useReducedMotion } from \"framer-motion\";\n\nexport function SpotlightCard({ children }: { children: React.ReactNode }) {\n const ref = useRef<HTMLDivElement>(null);\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n const opacity = useMotionValue(0);\n\n const smoothX = useSpring(mouseX, { stiffness: 300, damping: 30 });\n const smoothY = useSpring(mouseY, { stiffness: 300, damping: 30 });\n\n const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n if (!ref.current) return;\n const rect = ref.current.getBoundingClientRect();\n mouseX.set(e.clientX - rect.left);\n mouseY.set(e.clientY - rect.top);\n };\n\n return (\n <div\n ref={ref}\n onMouseMove={handleMouseMove}\n onMouseEnter={() => opacity.set(1)}\n onMouseLeave={() => opacity.set(0)}\n className=\"relative overflow-hidden border border-white/10 bg-black/20 p-8\"\n >\n <motion.div\n className=\"pointer-events-none absolute -inset-px\"\n style={{\n opacity,\n background: `radial-gradient(600px circle at ${smoothX}px ${smoothY}px, rgba(255,255,255,0.1), transparent 40%)`,\n }}\n />\n <div className=\"relative z-10\">{children}</div>\n </div>\n );\n}"
}
]
}