返回

磁吸按钮与光标跟随:一个公式的四种接法

把鼠标与元素中心的距离乘上强度,再用 lerp 平滑到位。同一公式接到位移、双层视差、CSS 高光和 3D 倾斜上。

磁吸按钮看起来像魔法,拆开只剩一行:把鼠标坐标与元素中心的距离,乘一个强度系数。剩下的差别只是把这个偏移接到哪里。

下面的演示是零依赖版。把鼠标移到按钮或卡片附近,就能看到四种接法。触屏设备会自动关掉位移和自定义光标。

磁吸光标演示

核心主张就一句:

offset = (鼠标 - 元素中心) × strength,再用 lerp 平滑到位。

磁吸按钮

三个关键决策:

感应范围要比按钮大。如果只在 mouseenter 时启动,按钮会突然跳一下。把矩形向外扩 90px,鼠标还没碰到,按钮已经迎上来。

必须用 lerp。直接赋值会跟鼠标死死黏住。0.15 的阻尼才有被吸过去的手感。

只用一个 requestAnimationFrame 循环。不要给每个按钮各绑一个 mousemove。全局记录坐标,统一在一个循环里算。

// public/demos/magnetic-cursor.html
const lerp = (a, b, t) => a + (b - a) * t;
const RADIUS = 90;

const inside =
  Math.abs(dx) < r.width / 2 + RADIUS &&
  Math.abs(dy) < r.height / 2 + RADIUS;

const tx = inside ? dx * m.strength : 0;
const ty = inside ? dy * m.strength : 0;
m.x = lerp(m.x, tx, 0.15);
m.y = lerp(m.y, ty, 0.15);
m.el.style.transform = `translate3d(${m.x}px, ${m.y}px, 0)`;

不在范围内时,目标值置 0,让 lerp 自己滑回去。

双层磁吸

让内部文字和图标用额外的 strength 再走一点,就会有轻微视差,按钮看起来有厚度:

<a class="btn magnet" data-strength="0.30">
  <span class="label" data-inner="0.20">查看案例</span>
  <span class="arrow" data-inner="0.45">→</span>
</a>

箭头走得比文字快,方向感会更清楚。

高光跟随

这一招完全不动 DOM,只写两个 CSS 变量,渲染交给 radial-gradient

.glow::before {
  pointer-events: none;
  background: radial-gradient(
    260px circle at var(--mx) var(--my),
    rgba(94, 159, 232, 0.45),
    transparent 72%
  );
}
glow.style.setProperty("--mx", mx - r.left + "px");
glow.style.setProperty("--my", my - r.top + "px");

伪元素必须写 pointer-events: none,否则高光层会拦住点击。

3D 倾斜

把鼠标位置归一化到 -11,再乘最大角度。X 轴要取反:鼠标向下时,卡片应该往后仰。

const nx = clamp((mx - cx) / (r.width / 2), -1, 1);
const ny = clamp((my - cy) / (r.height / 2), -1, 1);
const targetRotY = nx * 14;
const targetRotX = -ny * 14;

父元素必须有 perspective,否则旋转看起来是平的。700px 比较稳:小于 500px 会变形,大于 1200px 几乎看不出立体感。内容再用 translateZ(28px) 浮起来。

自定义光标

两个元素、两个不同的 lerp 系数,拖尾感就出来了:

dotX = lerp(dotX, mx, 0.40);  // 小点几乎跟手
ringX = lerp(ringX, mx, 0.14); // 外环明显滞后

隐藏系统光标时,必须加媒体查询,否则触屏设备会很难用:

@media (hover: hover) and (pointer: fine) {
  body { cursor: none; }
}
@media (hover: none) {
  .cursor-dot,
  .cursor-ring { display: none; }
}

想调手感时动这些数

参数当前值说明
磁吸强度0.300.35超过 0.5 会显得失控
感应范围90px小按钮可以给到 120
磁吸阻尼0.15越小越迟钝
内层额外位移0.20 / 0.45差值越大层次感越强
倾斜最大角14deg超过 20deg 会失真
光标外环阻尼0.14越小拖尾越长

在新页面打开完整演示。同专栏上一篇:滚动叙事长页