最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
用纯 CSS 和 JavaScript 实现自定义光标与动态聚光灯效果教程
时间:2026-07-11 11:19:46 编辑:袖梨 来源:一聚教程网
本文详解如何用 CSS radial-gradient 配合 CSS 变量和伪元素,创建可随鼠标移动、精准居中且真正“揭示内容”的聚光灯效果,避免 DOM 操作性能损耗。
本文详解如何用 css `radial-gradient` 配合 css 变量和伪元素,创建可随鼠标移动、精准居中且真正“揭示内容”的聚光灯效果,避免 dom 操作性能损耗。
要实现一个真正「揭示内容」的聚光灯效果(而非仅叠加发光圆),关键在于:将遮罩层(黑底+中心透光)作为背景层覆盖整个容器,并通过动态更新 background-position 实现光斑跟随鼠标移动。原方案中直接插入 <div> 并设置 radial-gradient 背景,本质上只是在顶层画了一个发光圆,无法穿透遮罩显示底层内容——这正是问题核心。
✅ 正确思路是:利用 .box::before 伪元素作为全屏遮罩层,其背景使用「中心透明 → 外圈全黑」的径向渐变;再通过 JS 实时更新 --flashlight-x-pos 和 --flashlight-y-pos 两个 CSS 自定义变量,驱动背景定位,让“光洞”始终对准鼠标位置。
以下是完整实现步骤:
1. HTML 结构(极简)
<div class="box"> <h1>Light</h1></div>
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('mouseleave', () => { // 鼠标离开时,将光斑移出视区,实现平滑隐藏 box.style.setProperty('--flashlight-x-pos', '-300px'); box.style.setProperty('--flashlight-y-pos', '-300px');});
✅ 关键优势说明:
- 真揭示效果:.box::before 的黑色遮罩层 + 中心透明区域,天然支持「透过光洞看到下方 <h1>」,无需额外图层叠加;
- 高性能:避免频繁 appendChild/style.left/top 操作,仅更新 CSS 变量,由浏览器原生优化渲染;
- 响应式友好:background-position 自动适配缩放与滚动,无需重算坐标;
- 可定制性强:修改 radial-gradient 参数即可调整光斑大小、边缘柔硬度、遮罩深浅(如 rgba(0,0,0,0.9) 更暗)。
⚠️ 注意事项:
- 确保 .box 有明确尺寸(如 width/height 或 padding),否则 getBoundingClientRect() 返回值可能不稳定;
- 若页面存在滚动,需监听 scroll 并重新计算 rect,或改用 e.offsetX/e.offsetY(但兼容性略低);
- 自定义光标图片建议使用 background-image 而非 <img> 标签,避免 pointer-events: none 导致的点击穿透问题。
通过该方案,你将获得一个轻量、流畅、语义清晰的聚光灯交互效果——它不只是视觉装饰,而是真正「照亮并揭示内容」的实用 UI 组件。
立即学习“Java免费学习笔记(深入)”;
相关文章
- 《重返未来1999》冷周六角色介绍:身份背景及剧情解析 07-11
- 重返未来1999无凹点如何打 07-11
- 明日方舟终末地卡缪火队如何打出输出 07-11
- 明日方舟终末地卡缪配队方法-卡缪火队阵容搭配攻略 07-11
- 刺客信条:黑旗 记忆重置艺术爱好者支线任务做法介绍 07-11
- 刺客信条:黑旗 记忆重置 全肖像画获得方法介绍 07-11