核心是将clientx/clienty映射为0–1比例值并存入css自定义属性,再用hsl()或color-mix()动态计算背景色,配合mouseleave重置、throttle节流及深色模式适配实现平滑自然的颜色响应。

监听鼠标移动并计算位置比例
核心是把 clientX 和 clientY 映射到 0–1 范围,方便后续作为 HSL 或 RGB 的插值系数。直接用 event.clientX / window.innerWidth 最简,但要注意:页面有横向滚动时 window.innerWidth 不包含滚动偏移,应改用 document.documentElement.scrollWidth;更稳妥的做法是用视口坐标除以视口尺寸(event.clientX / window.innerWidth + event.clientY / window.innerHeight),适用于全屏响应式场景。
- 避免用
pageX/pageY—— 它们受滚动影响大,容易导致颜色突变 - 加
throttle防止高频触发:用setTimeout节流到 60fps(约 16ms)足够平滑 - 移动端需额外监听
touchmove,且取touches[0].clientX
用 CSS 自定义属性暴露变量给 CSS
JS 不该直接操作元素的 style.color,而应更新根级自定义属性,让 CSS 自动响应。必须写在 :root 上,否则子元素无法继承;且属性名要语义清晰,比如 --mouse-x、--mouse-y,别用 --x 这类缩写,后期调试难定位。
- 设置时用
document.documentElement.style.setProperty('--mouse-x', xRatio),注意值是字符串,即使传数字也要转成xRatio.toString() - 初始值建议在 CSS 里设默认:
:root { --mouse-x: 0.5; --mouse-y: 0.5; },避免 JS 未执行前样式异常 - 不要在内联
style上设这些变量 —— 会污染 HTML,且无法被伪类或媒体查询复用
在 CSS 中用 hsl() 或 color-mix() 做动态插值
纯 CSS 实现颜色变化,最可控的是 hsl():把 --mouse-x 映射到色相(0–360),--mouse-y 映射到亮度(20%–90%)。Chrome 111+ 支持 color-mix(),可线性混合两种主色,写法更直观,但 Safari 目前不支持,得配降级方案。
background: hsl(calc(var(--mouse-x) * 360), 70%, calc(20% + var(--mouse-y) * 70%));- 若用
color-mix():background: color-mix(in srgb, red 30%, blue calc(70% - var(--mouse-x) * 70%)); - 务必加
transition: background 0.1s ease,否则颜色跳变生硬;但别设太长,超过 0.2s 会感觉滞后
处理边界与性能细节
鼠标移出窗口时 mousemove 事件停止触发,自定义属性值会卡在最后位置。这会导致离开后颜色“冻结”,必须监听 mouseleave 重置为默认值。另外,getComputedStyle 读取自定义属性开销低,但频繁读写仍可能触发重排 —— 所以只在必要时读(比如做条件判断),别在动画循环里反复读。
- 重置逻辑:
document.addEventListener('mouseleave', () => { document.documentElement.style.setProperty('--mouse-x', '0.5'); }); - 如果页面有 iframe 或 shadow DOM,
clientX/Y坐标需转换,否则映射失真 - 深色模式下,建议用
@media (prefers-color-scheme: dark)单独调亮暗两套 HSL 范围,避免夜间过亮刺眼
实际最难的不是写几行 JS 或 CSS,而是让颜色变化既自然又不抢眼——映射函数选线性还是缓动、色相跨度设 180° 还是 360°、是否加入饱和度扰动,这些微调全靠人眼判断,没法自动化。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











