
纯 CSS 的 :hover + mask 实现不了真正跟随鼠标的聚光灯效果,只能做静态焦点切换或区域高亮。 因为 mask-position 无法响应鼠标实时坐标,:hover 本身只作用于被悬停的元素,不是全局光标位置。强行用它模拟“跟随”,结果要么错位、要么卡顿、要么根本不动。
为什么 :hover 不能驱动聚光灯移动
聚光灯需要光心始终对齐鼠标指针,而 :hover 只在元素进入/离开时触发,且没有坐标参数。比如你给一个按钮加 :hover { mask-position: 20px 30px; },这个值是写死的,和鼠标当前 clientX/clientY 完全无关。更关键的是:一旦鼠标移出该元素,样式就重置,光斑直接消失——这根本不是“跟随”,只是“开关”。
-
:hover是布尔态,不是连续信号;CSS 里没有mouseX这类变量可绑定 -
mask的过渡(transition: mask-position)只在两个预设值之间插值,无法映射到动态坐标 - Firefox 直到 v96 才支持
mask的 transition,旧版直接跳变,:hover更不可靠
mask-image 配合 mask-position 的正确用法
真要用 mask 做聚光灯,必须放弃 :hover,改用 CSS 变量 + JS 更新。核心是让 mask-position 绑定 --x 和 --y,再由 JS 实时赋值:
div {
--x: 50%;
--y: 50%;
background: rgba(0,0,0,0.7);
-webkit-mask-image: radial-gradient(circle, black 0%, transparent 70%);
mask-image: radial-gradient(circle, black 0%, transparent 70%);
-webkit-mask-position: var(--x) var(--y);
mask-position: var(--x) var(--y);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
}
-
mask-position必须用px或%,不能用center—— 否则无法过渡 -
mask-image本身不能被 transition,只有mask-position和mask-size可过渡 - 移动端需注意:iOS Safari 对非
transform/opacity的 transition 会降级,建议用transform: translate()移动遮罩层而非改mask-position
容易被忽略的兼容性硬伤
哪怕代码写对了,以下三点不处理,聚光灯在真实设备上大概率失效:
-
pointer-events: none必须加在遮罩层上,否则它会挡住下方所有点击和 hover - 安卓 WebView 和部分旧版 Chrome 不支持
mask-image的径向渐变,得 fallback 到radial-gradient作为background遮罩 - 高 DPR 屏幕(如 MacBook Retina、iPhone)下,JS 获取的
pageX/pageY是物理像素,但 CSS 中的%基于逻辑像素,混用会导致光斑偏移 —— 推荐统一用px并除以window.devicePixelRatio
最麻烦的不是写法,而是「以为写了 :hover 就能动,结果上线才发现光斑钉死在左上角」—— 这种错觉比报错更难调试。真正可靠的方案,永远是 JS 控制变量 + CSS 响应式遮罩,而不是指望伪类猜中鼠标位置。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











