使用 CSS 圆形遮罩实现鼠标跟随的图片叠加揭示效果

1次阅读

使用 CSS 圆形遮罩实现鼠标跟随的图片叠加揭示效果

本文详解如何通过纯 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”,避免屏幕阅读器误读。

该方案彻底规避了嵌套绝对定位引发的图像“粘连”问题,结构解耦、样式可控、行为精准,适用于产品页视觉引导、图像对比展示、创意悬停交互等多种场景。

text=ZqhQzanResources