本文详解如何在保持文字原始渐变色(非纯色)的前提下,为每个字母添加 30px×30px 圆形悬停高亮区域,并确保悬停时仅呈现透明圆形遮罩叠加渐变效果,避免 fill: transparent 导致事件丢失,同时兼容 gsap 驱动的自定义光标动画。
本文详解如何在保持文字原始渐变色(非纯色)的前提下,为每个字母添加 30px×30px 圆形悬停高亮区域,并确保悬停时仅呈现透明圆形遮罩叠加渐变效果,避免 fill: transparent 导致事件丢失,同时兼容 gsap 驱动的自定义光标动画。
要实现「鼠标悬停单个字母时,在其位置生成一个 30×30px 的圆形渐变高亮区域」,关键在于分离视觉渲染与事件响应逻辑——不能依赖 <span> 自身变形(CSS border-radius 对内联文本无效),也不能将 fill: transparent 直接用于可交互 SVG 元素(会中断 pointer-events)。正确路径是:用绝对定位的 SVG 圆形作为「悬停指示器」,通过 JavaScript 动态追踪并偏移至目标字母的 boundingClientRect 中心,再结合 CSS mix-blend-mode 与渐变背景实现非侵入式高亮。
✅ 核心实现步骤
-
将文字逐字拆分为独立 <span> 并绑定事件
避免对整个 <h1> 统一处理,确保粒度精确到字母:
<div class="myText">
<h1>
<span class="color-letters" id="text-container"></span>
</h1>
</div>const text = "Get to know more about";
const container = document.getElementById("text-container");
container.innerHTML = text.split('').map(char =>
`<span class="letter" style="display:inline-block;">${char}</span>`
).join('');
// 为每个字母添加 hover 事件(使用事件委托更优)
container.addEventListener('mouseenter', (e) => {
if (e.target.classList.contains('letter')) {
const rect = e.target.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
// 触发自定义光标进入该字母中心
TweenMax.to(bigBall, 0.3, {
x: centerX - 15, // 30px 宽高 → 半径15
y: centerY - 15,
scale: 1, // 确保圆形尺寸固定为30×30
ease: Power2.easeOut
});
// 可选:为该字母临时添加 class 以触发局部样式变化(见下文)
e.target.classList.add('hovered');
}
});
container.addEventListener('mouseleave', (e) => {
if (e.target.classList.contains('letter')) {
e.target.classList.remove('hovered');
// 恢复默认光标位置(如返回 body 中心或上一位置)
}
});-
SVG 圆形需保留可交互性:用 pointer-events: auto 覆盖默认 none
原始代码中 .cursor__ball 设置了 pointer-events: none,这会导致无法监听其自身 hover —— 但此处我们不依赖 SVG 响应事件,而是由文字元素触发,因此 SVG 仅作视觉载体,必须确保其 fill 不为 transparent(否则 Safari/旧版 Chrome 可能忽略 hit-test),但又不能遮挡文字。解决方案是:
.cursor__ball circle {
fill: #f7f8fa; /* 保留可见填充色 */
opacity: 0.001; /* 几乎不可见,但保证事件穿透性 */
}
/* 或更优:使用混合模式 + 极低 alpha */
.cursor__ball circle {
fill: rgba(247, 248, 250, 0.01);
mix-blend-mode: difference; /* 与深色背景反色叠加,增强对比 */
}-
悬停时的渐变高亮:用伪元素 + background-clip 实现「圆形蒙版」
直接修改文字颜色会破坏原有渐变。正确做法是:为 .letter.hovered 添加一个 ::after 伪元素,定位在字母中心,设置 border-radius: 50%、width/height: 30px,并应用所需渐变:
.letter {
position: relative;
display: inline-block;
transition: opacity 0.2s;
}
.letter::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 30px;
height: 30px;
transform: translate(-50%, -50%);
border-radius: 50%;
background: linear-gradient(180deg, rgba(255, 33, 44, 0.5) 0%, rgba(25, 50, 25, 0.3) 100%);
z-index: 999;
opacity: 0;
pointer-events: none; /* 确保不拦截下层事件 */
transition: opacity 0.3s ease;
}
.letter.hovered::after {
opacity: 1;
}⚠️ 注意:.letter 必须设为 inline-block(非 inline),否则 ::after 的绝对定位将失效;pointer-events: none 在伪元素上是安全的,因事件仍由父 <span> 捕获。
-
保持原文本渐变:复用原有 background-clip: text 技术
你的原始 CSS 已正确实现静态渐变文字:
.letter {
background: linear-gradient(180deg, rgba(26, 33, 44, 0.5) 0%, rgba(255, 255, 255, 0.3) 100%);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
/* ...其他样式 */
}此写法与 ::after 高亮完全正交——渐变作用于文字本身,圆形高亮是独立图层,二者无冲突。
✅ 最终整合要点总结
- 不要尝试用 transform: scale() 或 border-radius 直接扭曲文字:文本是内联元素,无法直接圆角化。
- SVG 圆形仅作「跟随光标」视觉反馈,不承担事件逻辑:事件由文字 <span> 触发,SVG 仅做位置同步。
- 渐变高亮必须用独立图层(伪元素或额外 DOM):避免修改原始文字 background,确保常态与悬停状态互不干扰。
- 性能提示:若文本极长(>100 字),建议使用 IntersectionObserver 或节流 mouseenter,防止高频重绘。
通过以上结构,你既能维持优雅的线性渐变文字,又能实现像素级精准的圆形悬停反馈——既符合设计需求,也具备跨浏览器稳定性与可维护性。
立即学习“前端免费学习笔记(深入)”;










