核心是用 requestanimationframe 节流 mousemove,将图片 position 设为 absolute/fixed,监听 document 或容器并用 clientx/clienty 计算坐标,更新 transform 而非 left/top,移动端需兼容 touchmove 并 preventdefault。

用 mousemove 监听鼠标位置再更新图片坐标
核心是把图片的 position 设为 absolute 或 fixed,然后在 mousemove 事件里实时改它的 left 和 top。别想用 CSS 动画或 transition 搞“跟随”,那会延迟、卡顿、对不上鼠标位置。
常见错误:直接给图片加 transform: translate(...) 却没设 will-change: transform,滚动或快速移动时掉帧;或者监听了 document 却忘了图片在局部容器内,坐标没转成相对位置。
- 监听目标选
document最稳妥(覆盖全页),但若图片只在某个div内跟随,就监听那个容器,并用getBoundingClientRect()算相对偏移 - 记得用
e.clientX/e.clientY,不是e.pageX/e.pageY—— 后者含滚动距离,容易飘出视口 - 给图片加
pointer-events: none,否则它会挡住下层元素的点击和 hover
requestAnimationFrame 包一层再更新样式
直接在 mousemove 里改 style.left 会触发同步重排,高频下严重掉帧。浏览器每秒最多触发 60 次 mousemove,但你不需要每次响应 —— 用 requestAnimationFrame 节流,让更新节奏对齐屏幕刷新率。
不这么做的话,快速甩鼠标时图片会“拖影”或跳变,尤其在低配设备上明显。
立即学习“前端免费学习笔记(深入)”;
这是易秀购主题网转载的一款原创来至web主题公园的一款wordpress cms主题,非常适合做图片展示,或婚纱摄影类wordpress主题,采用了大气的网格化无缝设计,使列表以格子铺的方式排列,鼠标悬停的可以出现文章的简介。网站上方可以书写自己的广告语,图片也是可以替换掉的,图片会随着鼠标的移动而轻移,并且在鼠标滚动的时候,下面的模块会直接遮盖这个区域,这款wordpress cms主题视觉效果
- 声明一个
let pending = false标志位,避免重复进raf队列 - 在
mousemove里只存坐标(lastX/lastY),不操作 DOM -
raf回调里读取最新坐标,一次性更新style.transform(比left/top性能更好)
let lastX = 0, lastY = 0;
document.addEventListener('mousemove', e => {
lastX = e.clientX;
lastY = e.clientY;
if (!pending) {
pending = true;
requestAnimationFrame(() => {
img.style.transform = `translate(${lastX}px, ${lastY}px)`;
pending = false;
});
}
});
移动端要额外处理 touchmove
纯 mousemove 在手机上完全不触发。必须同时监听 touchstart + touchmove,且注意 touchmove 默认会触发页面滚动,得加 e.preventDefault()。
另一个坑:touches[0] 才是第一个触点,别错用 changedTouches(它只包含本次变化的触点,手指刚落时可能为空)。
- 监听
touchmove时,用e.touches[0].clientX取坐标 - 给目标元素加
touch-action: none,防止系统手势(如双指缩放)干扰 - 如果只希望单指拖动生效,检查
e.touches.length === 1再更新
图片本身别太大,也别用 background-image
用 <img alt="html如何做跟着鼠标动的动画图片" > 标签加载,宽高设死(比如 width: 40px; height: 40px;),避免 layout 波动。用 background-image 的话,得手动维护 background-position,计算更绕,且无法自然缩放或响应 srcset。
容易被忽略的一点:图片资源体积超过 100KB 时,首次跟随会有明显延迟(加载完才开始动)。优先用 SVG 或小尺寸 WebP。
- 给
<img alt="html如何做跟着鼠标动的动画图片" >加decoding="async",避免阻塞渲染 - 不要用
opacity做淡入,它会强制开启合成层,增加内存占用;改用visibility: hidden+ 定时器控制显隐 - 如果需要“吸附”效果(比如靠近边缘减速),别在每一帧都算物理公式——用 CSS
ease-out过渡transform更轻量









