核心是用 radial-gradient 创建中心透明、边缘渐变黑的圆形遮罩,通过 touchmove + requestanimationframe 动态更新 --x/--y 百分比坐标,配合伪元素::before 和 pointer-events: none 实现高性能、可穿透的移动端聚光灯效果。

在移动端 H5 中用径向渐变实现聚光灯高光效果,核心是用 radial-gradient 创建一个中心亮、边缘透明的圆形光斑,并让它随手指触点实时移动。关键不在“画个圆”,而在于让光斑精准贴合交互位置、保持视觉穿透性,同时兼顾性能和兼容性。
用 CSS radial-gradient 搭建基础光斑
聚光灯本质是一个带透明衰减的圆形遮罩层,不是叠加图层,而是“挖出”可见区域:
- 背景设为纯黑:
body { background: #000; } - 光斑层用伪元素
::before实现,避免干扰 DOM 和触摸事件 - 渐变写法示例:
background: radial-gradient(circle at var(--x) var(--y), transparent 0%, transparent 60%, rgba(0,0,0,0.8) 100%) - 注意:起始色必须是
transparent,否则中心不“透亮”;外圈用半透黑实现暗角过渡,避免生硬裁切
让光斑跟随手指移动(移动端适配)
移动端需监听 touchmove,且坐标要归一化到容器内百分比,才能适配不同屏幕尺寸:
- 给目标容器加
position: relative,确保坐标基准一致 - 在
touchmove中获取touches[0]坐标,用getBoundingClientRect()计算相对于容器左上角的x%和y% - 用
requestAnimationFrame节流更新 CSS 变量:el.style.setProperty('--x', x + '%'); - 务必加
pointer-events: none到光斑层,否则会拦截所有触摸操作
优化视觉与兼容性
原生渐变在部分安卓 WebView 或旧版 Safari 上表现不稳定,需主动兜底:
- 用
@supports (background: radial-gradient(circle at var(--x) var(--y), ...))包裹动态逻辑,仅支持时启用 - 不支持时降级为静态暗角:
background: url('vignette.png') no-repeat center / cover - 光斑半径建议用
min(40vw, 40vh)动态设定,避免在小屏上过大、大屏上过小 - 若内容含文字,可微调渐变 stop 位置(如
70%开始变暗),防止边缘文字被吞掉细节
不推荐直接用 Canvas 的原因
虽然 Canvas 的 createRadialGradient 更灵活,但在移动端做全屏聚光灯反而吃力:
- 需监听
touchmove后清屏重绘,频繁clearRect+fillArc易掉帧 - Canvas 坐标需手动适配 DPR,缩放后渐变参数易错位
- 无法自然穿透下层内容(比如按钮点击、视频播放控件),需额外处理事件转发
- CSS 方案天然硬件加速,内存占用低,更适合轻量 H5 场景











