自定义光标滚动时偏移消失,仅移动鼠标才恢复的问题求助
自定义光标滚动偏移问题的修复方案
问题根源
你的自定义光标使用position: absolute结合pageX/pageY定位,页面滚动时,光标位置基于文档坐标不会自动更新,导致光标偏移出视口;换成clientX/clientY后,由于absolute定位相对父元素(body),滚动幅度过大时,视口与文档的坐标差会让光标无法匹配鼠标实际位置。
两种修复方案
方案1:改用fixed定位(推荐)
将光标改为position: fixed,使其基于视口定位,配合clientX/clientY就能始终跟随鼠标,完全不受页面滚动影响。
修改CSS:
.cursor { pointer-events: none; position: fixed; /* 替换absolute为fixed */ width: 80px; height: 80px; border-radius: 50%; mix-blend-mode: exclusion; background: radial-gradient(circle, #000 0%, #000 3.99%, #fff 4%, #fff 100%); }
修改JS:
const cursor = document.querySelector('.cursor') document.addEventListener('mousemove', (e) => { // 用clientX/clientY,配合fixed定位,同时修正偏移量为40(光标宽高的一半) cursor.style.top = `${e.clientY - 40}px` cursor.style.left = `${e.clientX - 40}px` }) document.addEventListener("click", () => { cursor.classList.add('click') setTimeout(() => cursor.classList.remove('click'), 500) })
方案2:监听滚动事件更新位置
如果必须保留absolute定位,需要监听滚动事件,每次滚动时根据滚动距离调整光标位置,同时记录鼠标的文档坐标。
修改JS:
const cursor = document.querySelector('.cursor') let mouseX = 0 let mouseY = 0 // 记录鼠标的文档坐标 document.addEventListener('mousemove', (e) => { mouseX = e.pageX mouseY = e.pageY updateCursor() }) // 滚动时同步更新光标位置 document.addEventListener('scroll', updateCursor) function updateCursor() { // 减去光标自身一半的宽高,再减去滚动距离,让光标中心对准鼠标 cursor.style.top = `${mouseY - 40 - window.scrollY}px` cursor.style.left = `${mouseX - 40 - window.scrollX}px` } document.addEventListener("click", () => { cursor.classList.add('click') setTimeout(() => cursor.classList.remove('click'), 500) })
完整可运行代码(方案1)
HTML
<div class="cursor"></div> <h1>Hello world</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi nisi, congue at mattis in, fermentum at purus. In venenatis diam eget facilisis pharetra. Nam eget metus gravida nibh consectetur auctor. Nunc dignissim eros nunc, at tempus dui tincidunt quis. Mauris augue dui, pretium vel nunc ac, lacinia condimentum est. Maecenas mattis ligula non mi rutrum sodales. Aenean porta augue eget ex convallis, eget pulvinar felis accumsan. Suspendisse lorem nunc, dignissim at sapien eget, condimentum varius enim. Duis bibendum sed justo non laoreet. Ut egestas nisi vel interdum viverra. Ut consectetur ex sed sem pretium, convallis egestas tellus elementum. Maecenas libero felis, efficitur nec dolor et, ultrices dignissim magna.</p> <br>
CSS
@import url("https://fonts.googleapis.com/css?family=Montserrat:400,400i,700"); body { font-family: Montserrat, sans-serif; font-size: 30px; background: #000; color: #fff; cursor: none; min-height: 100vh; padding: 0; margin: 0; display: flex; flex-direction: column; justify-content: center; align-items: center; } div { display: inline-block; padding: 20px; } .cursor { pointer-events: none; position: fixed; width: 80px; height: 80px; border-radius: 50%; mix-blend-mode: exclusion; background: radial-gradient(circle, #000 0%, #000 3.99%, #fff 4%, #fff 100%); } .cursor.click { animation: click .3s ease-in-out; } @keyframes click { 0% { transform: scale(1); } 5% { transform: scale(1.3); } 100% { transform: scale(1); } }
JS
const cursor = document.querySelector('.cursor') document.addEventListener('mousemove', (e) => { cursor.style.top = `${e.clientY - 40}px` cursor.style.left = `${e.clientX - 40}px` }) document.addEventListener("click", () => { cursor.classList.add('click') setTimeout(() => cursor.classList.remove('click'), 500) })
内容的提问来源于stack exchange,提问作者Muhammad Abdullah
相关产品推荐
相关产品推荐

