悬停磁吸图标(指针靠近图标被吸附的磁力动效)
悬停磁吸图标组件:图标会朝指针方向偏移并被「吸附」,移开后弹性归位,rAF 指数插值实现平滑跟手,附带彩色光晕跟随,纯 JS 自研零依赖。
效果演示(真实可交互)
把鼠标移入任意一个图标附近,图标会朝指针方向偏移,像被磁铁吸住一样;同时图标外围浮起一圈同色光晕。指针在图标内移动时,图标会平滑跟手,而不是瞬间跳位;移出图标后,光晕淡去,图标弹性归位。五种图标各有独立的磁吸范围与光晕配色。
把指针移入图标附近,图标会被「磁吸」到指针方向,移开后弹性归位
完整代码
HTML(图标与光晕两层):
<div class="hmi-item">
<span class="hmi-icon">🎯</span>
<em class="hmi-ring"></em>
</div>
CSS(光晕默认隐藏,磁吸位移由内联 transform 驱动):
.hmi-ring {
position: absolute; inset: -10px; border-radius: 26px;
background: radial-gradient(circle, rgba(108,140,255,.4), transparent 70%);
opacity: 0; transition: opacity .25s ease;
pointer-events: none;
}
.hmi-icon { will-change: transform; }
JS(rAF 指数插值,指针跟手且平滑回弹,约 25 行):
const item = document.querySelector('.hmi-item');
const icon = item.querySelector('.hmi-icon');
const ring = item.querySelector('.hmi-ring');
let tx = 0, ty = 0, cx = 0, cy = 0, raf = null;
const loop = () => {
tx += (cx - tx) * 0.16; // 每帧向目标靠近 16%,指数趋近
ty += (cy - ty) * 0.16;
icon.style.transform = `translate(${tx}px, ${ty}px)`;
ring.style.opacity = cx || cy ? 1 : 0;
if (Math.abs(tx - cx) < .05 && Math.abs(ty - cy) < .05 && !cx && !cy) { raf = null; return; }
raf = requestAnimationFrame(loop);
};
item.addEventListener('pointermove', (e) => {
const r = item.getBoundingClientRect();
const maxX = r.width * 0.32, maxY = r.height * 0.32;
cx = Math.max(-maxX, Math.min(maxX, e.clientX - (r.left + r.width / 2)));
cy = Math.max(-maxY, Math.min(maxY, e.clientY - (r.top + r.height / 2)));
if (!raf) raf = requestAnimationFrame(loop);
});
item.addEventListener('pointerleave', () => { cx = 0; cy = 0; });
磁吸的核心是「指数插值」:指针移动时记录目标位移(限制在图标尺寸的 32% 以内防止跑飞),动画循环每帧向目标靠近 16%。这个系数决定了跟手度——系数越大越「黏」,越小越「飘」;指针离开时目标归零,图标自然弹回,无需单独的归位动画。
参数说明
| 参数 | 位置 | 说明 |
|---|---|---|
| 磁吸范围 | maxX / maxY 的 0.32 倍 | 限制最大偏移,防止图标脱离容器 |
| 跟手系数 | 插值常数 0.16 | 0.1-0.3,越大跟随越快越黏 |
| 光晕颜色 | .hmi-ring 的 radial-gradient | 按图标主题色各自配置 |
| 光晕过渡 | transition: opacity .25s | 控制光晕出现与消失的速度 |
| 触发事件 | pointermove / pointerleave | 统一桌面与触屏指针 |
兼容性与性能
- 只依赖 requestAnimationFrame 与 transform,所有现代浏览器原生支持
- 动画循环只在指针移动时启动,静止时自动停止,几乎零常驻开销
- transform 走 GPU 合成,多图标场景(10 个以内)无压力;若图标更多,可把 lerp 循环合并为全局单循环统一驱动
- 触屏设备上 pointermove 仅在按下拖动时触发,磁吸表现自然;不影响图标的 click 事件
常见问题
Q: 图标偏移后点击位置不准了? 磁吸位移只作用在图标元素上,外层的按钮容器没有移动,所以点击命中区域不变;若担心视觉与命中不一致,可给图标加 pointer-events: none,让事件始终落在容器上。
Q: 磁吸幅度不够或跑飞了? 幅度由 0.32 这个比例控制,调大它图标能吸得更远;「跑飞」通常是插值系数过大导致过冲,把 0.16 调小即可。
Q: 想让光晕跟随图标一起移动? 演示里光晕保持在图标附近同步位移,直接把光晕的 transform 也写成和图标相同的 translate 值即可,代码中已留出对应写法。
Q: 能商用吗? 可以。本组件为粤喵自研原创实现,免费商用无需署名。
许可与来源
- 许可证:自研原创 —— 粤喵自研原创,可免费用于个人与商业项目,无需署名。查看来源公示与许可清单
- 来源:粤喵团队原创自研(从效果思路到代码实现均为独立完成,未直接复制第三方代码)
- 首次发布:2026-09-01 · 最近更新:2026-09-01
- 修改日志:2026-09-01 首次发布;2026-09-13 补充许可证与来源标注、复制按钮说明与法务页入口
- 纠错:联系页面 / min@cactus.asia,2 个工作日内核实处理
常见问题
这个组件可以商用吗?
可以。本组件为粤喵自研原创,可免费用于个人和商业项目,无需署名。
浏览器兼容性如何?
支持所有现代浏览器(Chrome / Firefox / Safari / Edge 最新版本)。旧版 IE 不支持 CSS 动画相关特性。
怎么修改动画参数?
直接调整 CSS 中的 animation-duration(时长)、animation-timing-function(缓动曲线)等属性即可,代码中有注释说明。