纯CSS无法实现真正跟随鼠标的聚光灯动效,必须用JS动态更新radial-gradient圆心坐标;需用clientX/clientY减去容器rect位置获取相对坐标,伪元素遮罩并设pointer-events:none确保交互正常。

纯 CSS 无法实现真正跟随鼠标的聚光灯动效,必须配合 JS 动态更新坐标;否则你看到的只是静态偏移、hover 假象,或者根本不动。
radial-gradient 圆心位置不能直接用 CSS 变量
很多人写 radial-gradient(circle at var(--x) var(--y), ...),结果渐变不生效——因为 CSS 函数体内不解析变量值,浏览器会整条声明忽略。这不是语法错,是规范限制。
- 最稳方案:用 JS 拼接完整
background-image字符串,例如el.style.backgroundImage = `radial-gradient(circle at ${x}px ${y}px, ...)` - 若坚持用 CSS 变量,得靠
calc()绕过,比如radial-gradient(circle at calc(var(--x) * 1px) calc(var(--y) * 1px), ...),但要注意单位一致性(--x必须是纯数字) - 别用
pageX/pageY:它们含滚动偏移,页面一滚,光斑就“掉出”可视区
坐标必须归一化为容器内相对值
直接用 e.clientX 和 e.clientY 会导致光斑漂移,因为那是相对于整个视口的坐标,而聚光灯要对准的是目标容器内部。
- 先调
target.getBoundingClientRect()获取容器左上角在视口中的位置 - 再算相对坐标:
const x = e.clientX - rect.left,const y = e.clientY - rect.top - 推荐转成百分比(
x / rect.width * 100 + '%'),更适配响应式容器;若用像素,则需监听resize重算 - 移动端必须同时监听
touchmove,并从e.touches[0]取坐标,否则手指一动就失效
遮罩层必须用伪元素 + pointer-events: none
如果新增一个 实际最难调的不是 JS 绑定,是渐变半径和容器尺寸的比例关系。稍大一点,边缘就发虚;稍小一点,聚光范围又太窄。得反复用 devtools 调
.target::before 实现遮罩层:content: "" + position: absolute + inset: 0
pointer-events: none,否则底层交互全部失效z-index 要高于内容但低于可点击控件(如按钮),否则点不到关键元素rgba(0,0,0,0.7) 0%, transparent 70%,太深会吞掉文字细节,过渡段太短则边缘生硬--size 变量,而不是凭感觉估算。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











