游乐游手机版
首页/前端开发/文章详情

自定义光标与动态聚光灯效果的纯CSS和JavaScript教程

时间:2026-07-24 06:14
利用CSS径向渐变与伪元素创建黑底透光遮罩,通过JavaScript动态更新CSS自定义变量控制光斑位置,实现鼠标跟随聚光灯效果,避免频繁DOM操作,性能更优,精准揭示底层内容。
本文详细讲解如何借助 CSS radial-gradient、CSS 变量与伪元素,打造一个能够跟随鼠标移动、精准居中且真正“穿透遮罩以揭示内容”的聚光灯交互效果,同时有效避免 DOM 操作带来的性能损耗。

如果你曾被那种仅仅叠加一个发光圆、却无法穿透遮罩显示出底层内容的“伪聚光灯”所困扰,那么这篇文章正好能帮你彻底解决这个难题。其核心思路并不复杂:利用 CSS 的 radial-gradient 配合伪元素,构建一个“黑色背景 + 中心透光”的遮罩层,然后通过动态更新 background-position 属性,让光斑始终跟随鼠标移动。直接插入一个

并设置径向渐变背景,本质上只是在顶层绘制了一个圆形,根本无法穿透遮罩去显示下层内容——这才是问题的关键所在。

正确的实现方式是:将 .box::before 伪元素作为全屏遮罩层,其背景采用“中心透明 → 外圈全黑”的径向渐变;再通过 JavaScript 实时更新 --flashlight-x-pos--flashlight-y-pos 这两个 CSS 自定义变量,驱动背景定位,使“光洞”始终精准对准鼠标指针的位置。

下面直接进入具体实现步骤。

1. HTML 结构(极简)

Light

2. CSS 样式(核心遮罩逻辑)

.box {  display: flex;  align-items: center;  justify-content: center;  cursor: none;  width: 100%;  padding: 5rem;  background-color: #000;  overflow: hidden;  position: relative;  /* 初始光斑偏移至可视区外,实现“隐藏”效果 */  --flashlight-x-pos: -200px;  --flashlight-y-pos: -200px;  --flashlight-inset: -300px; /* 控制遮罩层大小,确保完全覆盖 */}/* 聚光灯遮罩层(伪元素) */.box::before {  content: '';  position: absolute;  inset: var(--flashlight-inset); /* 全向扩展遮罩 */  background-image: radial-gradient(    circle,    transparent 0%,     /* 中心完全透明 → 显示内容 */    rgba(0, 0, 0, 0.8) 60px,  /* 过渡到半透明灰黑 */    #000 70px,         /* 快速过渡为纯黑 */    #000 100%           /* 完全覆盖 */  );  background-position: var(--flashlight-x-pos) var(--flashlight-y-pos);  background-repeat: no-repeat;  z-index: 1;}/* 自定义光标(也用伪元素,减少 DOM 节点) */.box::after {  content: '';  position: absolute;  width: 50px;  height: 50px;  background: url('https://picsum.photos/50') no-repeat center / contain;  transform: translate(var(--flashlight-x-pos), var(--flashlight-y-pos));  pointer-events: none;  z-index: 2;}

3. JavaScript(高效定位 + 变量驱动)

const box = document.querySelector('.box');// ⚠️ 关键:getBoundingClientRect 在事件外计算一次,避免 mousemove 中重复调用(性能敏感!)const rect = box.getBoundingClientRect();box.addEventListener('mousemove', (e) => {  const x = e.clientX - rect.left;  const y = e.clientY - rect.top;  // 计算相对于容器中心的偏移量(使光斑自然居中)  box.style.setProperty('--flashlight-x-pos', `${x - rect.width / 2}px`);  box.style.setProperty('--flashlight-y-pos', `${y - rect.height / 2}px`);});box.addEventListener('mouselea ve', () => {  // 鼠标离开时,将光斑移出视区,实现平滑隐藏  box.style.setProperty('--flashlight-x-pos', '-300px');  box.style.setProperty('--flashlight-y-pos', '-300px');});

✅ 关键优势说明:

  • 真揭示效果.box::before 的黑色遮罩层搭配中心透明区域,天然支持“透过光洞看到下方

    内容”,完全无需额外图层叠加,实现真正的聚光灯穿透显示。

  • 高性能表现:无需频繁执行 appendChildstyle.left/top 操作,仅更新 CSS 变量,浏览器即可自行优化渲染流程,保证交互流畅度。
  • 响应式友好background-position 会自动适配容器缩放与页面滚动,无需手动重算坐标,在不同屏幕尺寸下表现稳定。
  • 可定制性强:调整 radial-gradient 的参数即可灵活控制光斑大小、边缘柔化程度以及遮罩透明度(例如使用 rgba(0,0,0,0.9) 可获得更暗的遮罩效果)。

⚠️ 注意事项:

  • 请确保 .box 具有明确的尺寸(如设置 width/heightpadding),否则 getBoundingClientRect() 的返回值可能不够稳定,影响光斑定位精度。
  • 如果页面存在滚动行为,需要监听 scroll 事件并重新计算 rect,或者改用 e.offsetX/e.offsetY(但其浏览器兼容性略低)。
  • 自定义光标图片建议使用 background-image 而非 标签,以避免 pointer-events: none 导致的点击穿透问题,确保交互体验完整。

通过以上步骤,你就能获得一个轻量、流畅且语义清晰的聚光灯交互组件——它不仅是视觉上的装饰,更是真正能够“照亮并揭示内容”的实用前端 UI 工具。

来源:https://www.php.cn/faq/2802049.html
上一篇CSS预处理器入门为何推荐选择Less作为最佳方案 下一篇CSS响应式布局防止视频元素溢出方法
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
JavaScript数组字面量与构造函数创建稀疏数组的差异
前端开发 · 2026-07-25

JavaScript数组字面量与构造函数创建稀疏数组的差异

数组字面量创建稠密数组,空位默认为undefined;Array()构造函数传入单个数字参数会生成稀疏数组,索引不存在且遍历方法跳过,多参数或非数字参数则行为与字面量一致。初始化稠密数组应使用Array from或fill。

如何优化Bootstrap按钮的焦点状态环CSS样式方法详解
前端开发 · 2026-07-25

如何优化Bootstrap按钮的焦点状态环CSS样式方法详解

Bootstrap按钮焦点样式优化需将内阴影改为外发光,覆盖所有焦点选择器避免原生蓝边闪烁。使用:focus-visible区分键盘与鼠标交互,同时处理按钮组圆角、父容器溢出及浏览器兼容性,确保焦点反馈清晰且符合无障碍标准。

Less中强制转换CSS单位适配不同移动端方案详解
前端开发 · 2026-07-25

Less中强制转换CSS单位适配不同移动端方案详解

Less单位转换需手动完成:用unit()剥离单位,通过变量控制基准值,再拼接目标单位。px2rem函数须区分输入类型(纯数字、带px单位等),基准值@base-font-size需全局定义且不可在媒体查询中重定义。所有运算发生在编译期,适配需提前编译多套CSS文件。

Vue 插件开发与使用完整指南
前端开发 · 2026-07-25

Vue 插件开发与使用完整指南

Vue插件通过install方法为应用注入全局属性、组件、指令、混入和provide等扩展能力,注册时机须在createApp之后、mount之前。插件支持对象或函数形式,使用app use()注册。开发时需注意命名冲突、配置默认值及错误处理,确保工程健壮性。

CSS响应式视频全屏黑边排版问题解决方案
前端开发 · 2026-07-25

CSS响应式视频全屏黑边排版问题解决方案

CSS响应式视频全屏黑边源于盒子模型、定位与加载策略缺失。需重置body边距及溢出,父容器用position:fixed与100dvh,video设为block+object-fit:cover。autoplay需加muted、playsinline。移动端用100dvh防地址栏抖动,低端机分辨率不超1倍。