通过JS设置top和left样式属性时出现诡异的不一致Bug
问题分析与解决方案
问题现象
创建固定定位的div并设置尺寸后,通过mousemove事件用offsetX/offsetY设置其left/top样式时,频繁出现属性被设为0px的情况;给元素添加transform: translate(-50px, -50px)后,错误赋值会变为50px,该问题在Chrome和Firefox中均存在。
问题根源
你误用了鼠标坐标属性:e.offsetX/e.offsetY是相对于事件触发目标元素的坐标,而非视口全局坐标:
- 当鼠标在页面空白区域移动时,事件目标是window或body,此时
offsetX/offsetY是视口内的全局坐标,设置left/top能正常生效; - 当鼠标移动到目标div上时,事件目标变为该div,此时
offsetX/offsetY是相对于div自身左上角的坐标(比如鼠标在div左上角时,offsetX就是0),设置left: 0px会让div瞬间跳到视口左上角,鼠标随即离开div,事件目标变回window/body,offsetX/offsetY又回到全局坐标,div被拉回,如此反复就出现了“半数赋值有效、半数变0”的现象; - 添加
transform: translate(-50px, -50px)后,div的布局原点被偏移,但offsetX/offsetY仍基于div的边界计算,鼠标触发div上的mousemove时,相对位置会对应偏移后的数值,最终出现50px的错误结果。
解决方案
改用e.clientX/e.clientY,这两个属性是相对于浏览器视口左上角的坐标,完全匹配固定定位元素left/top的参考系:
const mouse = document.getElementById('mouse'); window.addEventListener("mousemove", e => { mouse.style.left = e.clientX + 'px'; mouse.style.top = e.clientY + 'px'; });
补充优化
如果需要让元素中心点跟随鼠标(而非左上角),可以保留transform: translate(-50%, -50%)(用百分比适配元素自身尺寸),配合clientX/clientY使用,就能实现精准的鼠标跟随效果。
内容的提问来源于stack exchange,提问作者MushyShaman
相关产品推荐
相关产品推荐

