You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义圆形光标链接悬停放大效果不持久问题求助

Fixing the Flickering Circle Cursor Hover Effect

我明白你遇到的问题了——当鼠标悬停在链接上时,光标放大的效果几乎一闪而过,根本看不清。这其实是因为你的mousemove事件触发频率太高,每次都会直接修改光标元素的行内left和top样式,这会打断.grow类的过渡动画,导致缩放效果被频繁重置。

下面是修复后的完整代码,我会一步步解释修改点:

修改核心思路

  • 使用CSS变量来控制光标位置,避免行内样式和类样式的冲突
  • 拆分过渡效果,让位置移动和缩放动画互不干扰
  • 调整过渡时长,让缩放效果更明显

修复后的HTML(结构不变,仅确保光标层级)

<main>
 <div class="cr"></div>
 <div class="dot"></div>
 <div class="wrapper">
 <h1>simple circle cursor with <a href="#">hover</a> effect</h1>
 </div>
</main>

修复后的CSS

@import url('https://fonts.googleapis.com/css2?family=Red+Rose:wght@300;700&display=swap');

*,*::before,*::after {
 box-sizing: border-box;
}

body {
 position: relative;
 padding: 0px;
 margin: 0px;
 outline: 0;
 width: 100%;
 height: 600px;
 background-color: rgba(244,230,150,1);
 cursor: none;
 color: #e56b6f;
 /* 新增CSS变量存储光标坐标 */
 --cursor-x: 0;
 --cursor-y: 0;
}

.cr {
 position: absolute;
 /* 用CSS变量计算位置,替代行内样式 */
 left: calc(var(--cursor-x) - 30px);
 top: calc(var(--cursor-y) - 30px);
 width: 60px;
 height: 60px;
 background: transparent;
 border: 1px solid #000;
 border-radius: 100%;
 /* 拆分过渡:位置移动保持流畅,缩放效果延长时长 */
 transition: transform 200ms ease, left 80ms ease, top 80ms ease;
 /* 确保光标在最上层,不被其他元素遮挡 */
 z-index: 9999;
}

.dot {
 position: absolute;
 left: calc(var(--cursor-x) + 7px);
 top: calc(var(--cursor-y) + 7px);
 width: 5px;
 height: 5px;
 background: black;
 border-radius: 100%;
 transition: left 80ms ease, top 80ms ease;
 z-index: 9999;
}

main {
 display: flex;
 justify-content: flex-end;
 padding: 50px
}

.wrapper {
 max-width: 600px;
}

h1 {
 font-family: 'Red Rose', cursive;
 font-size: 60px;
 line-height: 60px;
 text-align: right;
}

a {
 color: #e56b6f;
 text-decoration: none;
}

.grow {
 transform: scale(1.5);
}

修复后的JavaScript

const circle = document.querySelector(".cr");
const dot = document.querySelector(".dot");
const body = document.querySelector("body");
const links = Array.from(document.querySelectorAll("a"));

body.addEventListener("mousemove", function(e) {
 const x = e.clientX;
 const y = e.clientY;
 // 更新CSS变量,而非直接修改元素行内样式
 body.style.setProperty('--cursor-x', x + 'px');
 body.style.setProperty('--cursor-y', y + 'px');
});

links.forEach(item => {
 item.addEventListener("mouseenter", () => {
 circle.classList.add("grow");
 });
 item.addEventListener("mouseleave", () => {
 circle.classList.remove("grow");
 });
});

关键修改点解释

  1. CSS变量替代行内样式:
    原来的代码每次mousemove都直接给光标元素设置行内位置样式,会频繁触发重绘并打断缩放过渡。改用CSS变量后,位置更新通过全局变量传递,不会和.grow类的transform属性冲突,过渡动画能完整执行。

  2. 拆分过渡效果:
    把统一的all过渡拆分成位置和缩放的独立动画,位置移动用80ms保证光标跟随流畅,缩放用200ms让放大效果清晰可见。

  3. 添加z-index:
    确保光标元素在页面最上层,避免被其他内容遮挡,保证视觉效果正常。

现在你可以测试一下,悬停链接时光标会平滑放大,离开后又会自然缩回,效果非常明显!

内容的提问来源于stack exchange,提问作者Paulette

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 20:22:36