Frontend Lab
← 回到所有效果
F08A033framer-motion

Magnetic Button

磁吸按鈕

難度 ★★★★★標籤 hover · 磁吸 · useSpring3 min read

效果簡述

游標靠近按鈕時,按鈕「被吸過去」一點。是 Awwwards 系作品常見的招。 核心是 mouseX - centerX 乘 0.2~0.3 的位移 + spring 平滑。

預設|倍率 0.3, spring 200/18

Claude Code Prompt

💬 Claude Code Prompt
參考:A033 magnetic button
技術:framer-motion useMotionValue + useSpring

具體行為:
- 包一層 wrapper(hit area 比按鈕大一點,padding 加大)
- onMouseMove: const rect = e.currentTarget.getBoundingClientRect()
- x.set((e.clientX - (rect.left + rect.width/2)) * 0.3)
- y.set((e.clientY - (rect.top + rect.height/2)) * 0.3)
- onMouseLeave: x.set(0); y.set(0)
- 用 useSpring 包 x/y → stiffness 200 damping 18

限制:
- 倍率 0.2 ~ 0.4 之間(再多就鬼魅)
- 手機沒效果(記得加 @media (hover: hover))
- 一頁不要超過 3 個(會搶焦點)

完整程式碼

MagneticButton.tsx
'use client'

import { motion, useMotionValue, useSpring } from 'framer-motion'

export function MagneticButton({ children = 'Hire me' }: { children?: React.ReactNode }) {
const x = useMotionValue(0)
const y = useMotionValue(0)
const sx = useSpring(x, { stiffness: 200, damping: 18 })
const sy = useSpring(y, { stiffness: 200, damping: 18 })

function onMove(e: React.MouseEvent<HTMLDivElement>) {
  const r = e.currentTarget.getBoundingClientRect()
  x.set((e.clientX - (r.left + r.width / 2)) * 0.3)
  y.set((e.clientY - (r.top + r.height / 2)) * 0.3)
}
function onLeave() {
  x.set(0)
  y.set(0)
}

return (
  <div onMouseMove={onMove} onMouseLeave={onLeave} className="p-8">
    <motion.button
      style={{ x: sx, y: sy }}
      className="rounded-full bg-foreground px-6 py-3 font-medium text-background"
    >
      {children}
    </motion.button>
  </div>
)
}

何時用

  • ✅ Hero CTA(要醒目又有質感)
  • ✅ 作品集 contact 按鈕
  • ✅ 重點轉換點(訂閱、下載)

何時別用

  • ❌ 一般表單按鈕(會分心)
  • ❌ Nav menu items(hover 一堆東西在跳)
  • ❌ 手機為主的站(沒 hover 完全失效)

我踩過的坑

  1. wrapper hit area 太小:onMouseMove 綁在按鈕本身的話,按鈕一被 吸走就脫離了 hit area,會抖。一定要包外層更大的 div。

  2. 沒用 useSpring:直接綁 x/y 是「跟著游標瞬移」,沒磁吸感。 spring 才有「被吸過去再彈回」的物理感。

  3. 手機沒處理:mobile 上 mousemove 不會觸發,但 layout 還在。 要包 @media (hover: hover) 或檢查 matchMedia('(pointer: fine)')

相關效果

搜尋

按 ⌘K 隨時開啟