
本文详解如何通过纯 css + javascript 实现“下层图片常驻、上层图片仅在鼠标悬停处以圆形(可带渐变)遮罩动态揭示”的交互效果,解决因绝对定位嵌套导致的图像偏移问题。
本文详解如何通过纯 css + javascript 实现“下层图片常驻、上层图片仅在鼠标悬停处以圆形(可带渐变)遮罩动态揭示”的交互效果,解决因绝对定位嵌套导致的图像偏移问题。
要实现「鼠标移动时,在固定位置的底层图片上,用一个可跟随光标的圆形窗口揭示上方图片」的效果,关键在于分离“遮罩容器”与“被揭示内容”的定位逻辑——不能将上层图片嵌套在移动的 .circle 内并设为 position: absolute,否则它会随 .circle 一起位移,导致始终只显示同一区域。
正确的思路是:
✅ 将两幅图片均作为 背景图(background-image) 分别应用在两个层级分明的 DOM 元素上;
✅ 底层容器(.container)承载下层图片,并设置 overflow: hidden 限制可见范围;
✅ 上层遮罩(.circle)是一个独立的、可自由移动的圆形 div,其自身设置上层图片为背景,通过 background-position 动态对齐视口;
✅ JavaScript 仅控制 .circle 的 left/top 坐标,使其中心始终锚定鼠标位置。
✅ 推荐 HTML 结构(语义清晰、无冗余嵌套)
<div class="container" style="background-image: url('lower.png')">
<div class="circle" style="background-image: url('upper.png')"></div>
</div>✅ 核心 CSS(重点:背景定位 + 居中控制)
.container {
position: relative;
width: 100vw; /* 或具体尺寸,如 1920px */
height: 100vh; /* 或具体尺寸,如 1280px */
background-size: cover;
background-position: center;
overflow: hidden;
border-radius: 0; /* 若需整体圆角可设,但非必须 */
}
.circle {
position: absolute;
width: 200px; /* 遮罩直径 */
height: 200px;
border-radius: 50%;
background-size: cover;
background-position: center;
/* 初始居中(可选),后续由 JS 覆盖 */
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 2;
/* 可选:添加内阴影或渐变蒙版增强视觉层次 */
box-shadow: 0 0 0 9999px rgba(0,0,0,0.3);
}
/* 添加柔和渐变边缘(可选增强效果)*/
.circle::before {
content: "";
position: absolute;
inset: 0;
border-radius: 50%;
background: radial-gradient(
circle at center,
transparent 0%,
transparent 70%,
rgba(0, 0, 0, 0.4) 100%
);
}? 注意:box-shadow 技巧(超大模糊半径遮罩)比 overflow: hidden 更可靠,能避免 .circle 移出容器时出现意外裁剪;若需严格限制在 .container 内,可改用 clip-path: circle(100px at var(--x) var(--y)) 配合 CSS 变量(现代浏览器支持)。
✅ 精准跟随的 JavaScript(修正原逻辑缺陷)
const container = document.querySelector('.container');
const circle = document.querySelector('.circle');
const radius = 100; // 半径 = 宽高 / 2
container.addEventListener('mousemove', (e) => {
const rect = container.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// 设置 circle 的中心点为 (x, y),需减去半径实现“锚点居中”
circle.style.left = `${x - radius}px`;
circle.style.top = `${y - radius}px`;
// 同步更新背景定位,确保上层图片内容随遮罩稳定呈现(关键!)
circle.style.backgroundPosition = `${-x + radius}px ${-y + radius}px`;
});? 为什么需要 backgroundPosition 动态调整?
因为 .circle 是移动的容器,而它的背景图(上层图片)默认以自身左上角为原点。要让“鼠标所在位置”始终对应上层图片的同一物理坐标(即实现“窥视”而非“平移”),就必须反向偏移背景图——即 background-position 设为 -(x - r), -(y - r),抵消容器位移。
✅ 进阶优化建议
- 性能优化:对 mousemove 使用 throttle(如 Lodash 的 throttle 或 requestAnimationFrame 包裹),避免高频重排;
- 响应式适配:用 vmin 单位定义 .circle 尺寸(如 width: 20vmin; height: 20vmin;),并动态计算 radius;
- 触屏兼容:补充 touchmove 事件监听,并从 e.touches[0] 读取坐标;
- 无障碍友好:为 .circle 添加 aria-hidden="true",避免屏幕阅读器误读。
该方案彻底规避了嵌套绝对定位引发的图像“粘连”问题,结构解耦、样式可控、行为精准,适用于产品页视觉引导、图像对比展示、创意悬停交互等多种场景。










