pointer-events: none 是解决聚光灯遮罩层拦截鼠标事件的唯一可靠方法,需应用于遮罩层及伪元素;配合 radial-gradient 或 mask-image 实现镂空,并通过 requestAnimationFrame 节流同步 --x/--y 坐标以确保精度与性能。

用 pointer-events: none 让聚光灯不干扰交互
聚光灯效果本质是遮罩层 + 圆形镂空,但遮罩层如果默认响应鼠标事件,会挡住下方按钮、链接等元素。必须显式禁用其事件捕获:pointer-events: none 是唯一可靠解法。否则会出现“看起来能点,实际点不动”的问题。
常见错误是只给遮罩加 opacity 或 z-index,却忘了这层 DOM 依然在事件流中。只要遮罩层存在且未设 pointer-events: none,它就吃掉所有鼠标事件。
- 遮罩层(如
.spotlight-mask)必须设pointer-events: none - 镂空区域本身不能是独立元素——它只是遮罩上的透明洞,靠
radial-gradient或mask-image实现 - 如果用伪元素实现遮罩,同样要加
pointer-events: none,否则伪元素也会拦截事件
用 radial-gradient 做纯 CSS 镂空,兼容性好且无需 JS
不需要 JavaScript 就能实现基础聚光灯:用一个全屏遮罩层,背景设为黑色半透的径向渐变,中心透明,边缘不透明。关键在渐变参数控制“光斑”大小和软硬边缘。
radial-gradient(circle at var(--x) var(--y), transparent 0%, transparent 50px, rgba(0,0,0,0.7) 50px) 这样的写法里,50px 决定光圈半径;两个 50px 对齐才能保证边缘锐利;若第二个值更大(如 60px),就会出现羽化过渡。
立即学习“前端免费学习笔记(深入)”;
-
--x和--y是 CSS 自定义属性,需通过 JS 动态更新,但渐变逻辑本身完全由 CSS 承担 - 不要用
background-position模拟移动——它无法精准对齐鼠标坐标,且动画卡顿 - IE 不支持
radial-gradient的at语法,如需兼容 IE,得退回到 JS 控制clip-path方案
用 mask-image 实现更精细的光斑形状与混合模式
当需要椭圆光斑、带噪点纹理或叠加多重光晕时,mask-image 比 radial-gradient 更灵活。它允许你用 PNG、SVG 或 CSS 渐变作为遮罩源,且支持 mask-composite 组合多个遮罩。
例如:mask-image: radial-gradient(circle at var(--x) var(--y), black 0%, transparent 100%),配合 mask-mode: alpha,可让遮罩直接作用于元素自身 Alpha 通道,避免颜色叠加干扰。
-
mask-image在 Safari 15.4+、Chrome 101+、Firefox 110+ 稳定支持;旧版 Chrome 需加-webkit-mask-image - 使用 SVG 作为 mask source 时,务必确保 SVG 文件内无宽高硬编码,否则缩放失真
- 若同时用
backdrop-filter做毛玻璃效果,mask-image会正常作用于滤镜后画面,而background-blend-mode则不会
监听 mousemove 并防抖更新 --x/--y 变量
鼠标坐标必须实时同步到 CSS 变量,但频繁触发 mousemove 会导致重绘压力。直接在事件回调里设 style.setProperty 很危险——每帧都可能触发 layout → paint 流程。
真正有效的做法是:用 requestAnimationFrame 节流,把坐标更新收敛到浏览器下一帧;同时用 clientX/clientY 而非 pageX/pageY,避免滚动时坐标错位。
- 别用
debounce库函数封装mousemove——它会引入延迟,导致光斑“拖尾” - 更新变量前先判断坐标是否变化超过 2px,小幅度抖动可忽略,减少无效样式计算
- 移动端需额外监听
touchmove,且要用touches[0].clientX,注意 touch 事件默认可滚动,需event.preventDefault()阻止


















