光晕动效核心是用css自定义属性实时更新--x、--y和--blur,结合radial-gradient定位与filter: blur()合成;js通过requestanimationframe节流监听mousemove,将鼠标坐标转为容器内0–100%值写入变量,避免像素硬编码与高频触发。

光晕动效的核心原理是啥
不是靠 transform 硬位移,也不是用 box-shadow 堆叠多层——而是用 CSS 自定义属性实时更新光晕的 --x、--y 和扩散半径,再通过 filter: blur() + radial-gradient 合成动态光晕。JS 只负责监听鼠标位置并写入变量,CSS 负责渲染,这样动画不卡顿、不触发重排。
关键点在于:光晕本身不能是真实 DOM 元素(否则要频繁增删),必须用伪元素或背景渐变实现;且变量更新要节流,否则高频触发会拖慢主线程。
怎么用 JS 把鼠标坐标写进 CSS 变量
监听 mousemove 事件,把 clientX 和 clientY 转为相对于目标容器的百分比值(更利于响应式),再用 style.setProperty() 写入根或容器级变量:
常见错误是直接写像素值,导致在缩放/滚动/高 DPR 屏幕下偏移错位;或者没做节流,mousemove 每秒触发上百次,CPU 升温。
- 用
requestAnimationFrame节流,比throttle更精准匹配帧率 - 坐标统一转为
0–100范围,比如:(e.clientX - rect.left) / rect.width * 100 - 写入
:root或目标元素的style,避免污染全局,例如:target.style.setProperty('--x', x) - 别忘了处理
mouseleave,设回默认值防止光晕悬空
CSS 里怎么用变量画出可跟随的光晕
核心是用 background 配合 radial-gradient 定位,再叠加 blur() 滤镜模拟发光扩散:
background: radial-gradient(circle at var(--x, 50%) var(--y, 50%), rgba(255, 255, 255, 0.6), transparent 70%); filter: blur(var(--blur, 20px));
注意几个坑:
-
radial-gradient的at位置必须用var(--x),不能写成calc(var(--x) * 1px)—— CSS 不支持变量参与 calc 单位运算 -
filter: blur()不能加在伪元素上再设pointer-events: none,否则 iOS Safari 会失效,得套一层div或直接作用于容器 - 如果光晕太“实”,调低
rgba透明度;如果边缘锯齿,提高blur值并确保父容器有will-change: filter
为什么光晕总滞后或跳变
多数情况是坐标没对齐参考系:JS 读的是视口坐标,CSS 渐变定位却基于元素自身盒模型。尤其当容器有 transform、scroll 或 scale 时,偏差立刻暴露。
解决办法只有一个:所有坐标计算必须基于 getBoundingClientRect() 实时获取的 rect,而不是 offsetLeft/Top 或硬编码宽高。另外,blur 值别设太大(超过 40px 在低端机容易掉帧),优先调透明度和渐变范围来控制“虚化感”。
真正难的不是写出来,是让光晕在滚动、缩放、深色模式切换、甚至 iframe 里都稳住位置——那得把 resize、scroll、orientationchange 全部纳入坐标重算链路,变量更新就不再是简单的一句 setProperty 了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











