如果你用过Windows 10的设置界面,一定会对那个标志性的视觉效果印象深刻:页面整体处于半暗状态,而鼠标所在的位置就像被一束探照灯照亮,形成一个柔和的圆形高光区域,随着光标移动,光照范围也随之流动。这个效果既提升了界面的质感,又起到了视觉引导作用。本文将从原理拆解入手,带你用CSS和JavaScript在自己的网页中复刻这种探照灯效果,并提供多种实现方案与性能优化建议。

探照灯效果的核心原理是什么
要理解探照灯效果,首先要明白它本质上是一个遮罩问题。想象一张图片被一块黑色幕布盖住,幕布上挖了一个圆洞,洞的位置跟随鼠标移动,于是图片只有洞口对应的部分是亮的,其余部分是暗的。在CSS中,这个幕布可以通过mask-image属性实现,而圆形洞口则用径向渐变radial-gradient来绘制。
具体来说,径向渐变从圆心到边缘的颜色过渡是从透明到黑色。当把它作为遮罩应用到某个元素上时,透明区域的元素内容可见,黑色区域的元素内容被隐藏。如果反过来使用,把一个半透明的黑色遮罩层套在内容上方,再在遮罩层上挖出透明圆孔,就得到了我们想要的探照灯效果。
关键在于如何让这个圆孔跟随鼠标移动。传统做法是直接用JavaScript修改元素的style属性,但更现代、性能更好的方式是使用CSS自定义属性(变量)。JavaScript只需要更新--mouse-x和--mouse-y两个变量,CSS中的渐变公式引用这些变量,浏览器会自动重绘。这种方式把样式计算完全交给CSS引擎,避免了频繁的字符串拼接和解析开销。
纯CSS方案:利用CSS变量与伪元素
第一种方案几乎不需要写JavaScript逻辑,只需要几行监听代码。结构上,外层容器作为探照灯的作用区域,内部放真实内容,伪元素作为遮罩层覆盖在上面。
<div class="spotlight-box">
<p>这里是被探照灯照亮的内容区域,鼠标移入后可以看到高光跟随效果。</p>
</div>
<style>
.spotlight-box {
--mouse-x: 50%;
--mouse-y: 50%;
position: relative;
height: 300px;
background: #1a1a2e;
overflow: hidden;
}
.spotlight-box::before {
content: "";
position: absolute;
inset: 0;
/* 径向渐变:圆心透明,四周黑色半透明 */
background: radial-gradient(
circle 180px at var(--mouse-x) var(--mouse-y),
transparent 0%,
rgba(0, 0, 0, 0.9) 70%
);
pointer-events: none; /* 不阻挡鼠标事件 */
}
</style>上面代码中,circle 180px定义了光照半径,at var(--mouse-x) var(--mouse-y)指定了圆心位置。遮罩层使用pointer-events: none非常重要,否则伪元素会拦截鼠标事件,导致监听失效。
接下来只需要一小段JavaScript,在鼠标移动时更新变量值。注意这里用的是setProperty方法,它只修改变量本身,不会触发样式的全量重算,性能远好于直接改style.background。
const box = document.querySelector('.spotlight-box');
box.addEventListener('mousemove', (e) => {
// 获取鼠标相对容器的坐标
const rect = box.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// 更新CSS变量,单位为像素
box.style.setProperty('--mouse-x', x + 'px');
box.style.setProperty('--mouse-y', y + 'px');
});
box.addEventListener('mouseleave', () => {
// 鼠标离开时恢复到中心
box.style.setProperty('--mouse-x', '50%');
box.style.setProperty('--mouse-y', '50%');
});这种方案的优点是实现简单、兼容性好,所有主流浏览器都支持CSS变量和径向渐变。缺点是当元素尺寸很大时,径向渐变的重绘成本会随之上升,不过在绝大多数场景下这不是问题,因为渐变重绘由GPU加速完成,通常能稳定保持60帧。
进阶方案:叠加文字镂空与双层光效
Windows 10设置界面的效果其实比单一遮罩更丰富:除了照亮背景,它还会让遮罩区域的文字透出来,形成一种透过黑暗看到内容的感觉。这可以用双层结构实现:底层是完整的内容,顶层是一个深色覆盖层,覆盖层上用mask-image挖出跟随鼠标的圆孔。
<div class="spotlight-text">
<div class="content-layer">
<h3>系统设置</h3>
<p>设备和打印机、轻松使用、隐私、更新和安全</p>
</div>
<div class="overlay-layer"></div>
</div>
<style>
.spotlight-text {
position: relative;
height: 300px;
cursor: default;
}
.content-layer {
padding: 40px;
background: linear-gradient(135deg, #0f3460, #16213e);
color: #fff;
}
.overlay-layer {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.85);
/* 用mask挖出圆孔,让底层内容透出 */
-webkit-mask-image: radial-gradient(
circle 150px at var(--mx, 50%) var(--my, 50%),
transparent 0%, black 75%
);
mask-image: radial-gradient(
circle 150px at var(--mx, 50%) var(--my, 50%),
transparent 0%, black 75%
);
}
</style>这里的变量定义在.spotlight-text容器上,JavaScript的监听代码与前一节相同,只需把选择器换掉。注意mask-image目前仍需要-webkit-前缀以兼容部分浏览器,两个属性都要写。
如果想让光照边缘更柔和,可以调整渐变的中间值,例如把transparent 0%, black 75%改成transparent 30%, rgba(0,0,0,0.5) 60%, black 75%,这样会形成一个从亮到暗的平滑过渡带,视觉上更像真实光源的衰减效果。
另一个增强技巧是在圆心处再叠加一层白色径向光晕,模拟光源本身的辉光。可以在内容层上方再加一个伪元素,绘制一个从rgba(255,255,255,0.15)到透明的渐变,圆心位置同样引用鼠标变量,并设置mix-blend-mode: screen混合模式,让光晕与背景自然融合。
性能优化与常见问题处理
鼠标移动事件触发频率非常高,一秒可能触发上百次,如果每次都直接操作样式,容易造成掉帧。最直接的优化手段是使用requestAnimationFrame做节流:只在浏览器每一帧渲染前更新一次坐标,多余的移动事件被合并处理。
let rafId = null;
let pendingX = 0, pendingY = 0;
box.addEventListener('mousemove', (e) => {
const rect = box.getBoundingClientRect();
pendingX = e.clientX - rect.left;
pendingY = e.clientY - rect.top;
if (rafId === null) {
rafId = requestAnimationFrame(() => {
box.style.setProperty('--mouse-x', pendingX + 'px');
box.style.setProperty('--mouse-y', pendingY + 'px');
rafId = null;
});
}
});此外,getBoundingClientRect本身也有一定开销,可以在页面滚动或resize时缓存坐标,而不是每次鼠标移动都重新计算。对于固定定位的元素,甚至可以在初始化时计算一次即可。
还有一个常见问题是触屏设备的适配。手机和平板上没有持续的鼠标移动,探照灯效果失去意义,此时可以通过matchMedia('(hover: hover)')检测设备是否支持悬停,不支持时直接展示完整内容,不做遮罩处理。也可以监听touchmove事件,让探照灯跟随手指移动,作为触摸交互的替代方案。
最后需要提醒,遮罩层务必记得加pointer-events: none,这是新手最容易踩的坑。如果没有这个属性,遮罩层会拦截所有点击,导致下方的按钮、链接无法响应,用户会以为页面坏了。排查这类问题时,可以临时给遮罩层加个红色边框,确认它的覆盖范围和事件阻挡情况。
总结
探照灯效果的实现思路可以归纳为一句话:用径向渐变画光圈,用CSS变量传坐标,用JavaScript追踪鼠标。三种方案各有侧重:纯CSS变量方案简单可靠,适合大多数页面;双层镂空方案还原度最高,最接近Windows 10设置界面的观感;而性能优化中的requestAnimationFrame节流和悬停检测则保证了效果在各种设备上都能流畅运行。掌握这些技巧后,你还可以举一反三,把径向遮罩换成线性遮罩或锥形遮罩,创造出扫描线、雷达等更多有意思的光影交互效果。
CSS探照灯效果JavaScript动画Windows 10设置界面修改时间:2026-09-01 02:01:09