You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现点击穿透父div触发子div点击事件且不影响父div的::before属性

问题

我开发了一款带有“手电筒”效果的游戏:蓝色半透明盒子(#puzzle3bg)通过手电筒区域显示内部移动的圆圈。现在需要保留手电筒效果的同时,让点击能穿透#puzzle3bg,触发下方圆圈元素的onclick事件。尝试使用pointer-events属性时,要么手电筒效果失效,要么子元素仍无法响应点击,求解决方法。

原代码

HTML

<div id="puzzle3">
  <div id="puzzle3box">
    <div class="p3correctCircle"></div>
    <div class="p3correctCircle"></div>
    <div class="p3correctCircle"></div>
    <div class="p3wrongCircle"></div>
    <div class="p3wrongCircle"></div>
    <div class="p3wrongCircle"></div>
    <div class="p3wrongCircle"></div>
    <div class="p3wrongCircle"></div>
  </div>
  <div id="puzzle3bg"></div>
</div>

CSS

#puzzle3 {
  display: inline-block;
  text-align: center;
}

#puzzle3bg {
  display: block;
  width: 750px;
  height: 750px;
  --cursorX: 375px;
  --cursorY: 375px;
}

#puzzle3bg::before {
  content: "";
  display: block;
  width: 750px;
  height: 750px;
  position: relative;
  background: radial-gradient(
    circle 100px at var(--cursorX) var(--cursorY),
    rgba(170,255,255,.3) 0%,
    rgba(170,255,255,.6) 80%,
    rgba(170,255,255,1) 100%
  );
  z-index: 10;
}

.p3correctCircle {
  display: inline-block;
  position: absolute;
  background: #00FF00;
  border-radius: 50%;
  width: 50px;
  height: 50px;
  transition-duration: 600ms;
  z-index: 0;
}

.p3wrongCircle {
  display: inline-block;
  position: absolute;
  background: #FF0000;
  border-radius: 50%;
  width: 50px;
  height: 50px;
  transition-duration: 600ms;
  z-index: 0;
}

JS

function updateCursor(e) {
  var x = e.offsetX
  var y = e.offsetY
  document.getElementById("puzzle3bg").style.setProperty('--cursorX', x + 'px')
  document.getElementById("puzzle3bg").style.setProperty('--cursorY', y + 'px')
}

document.getElementById("puzzle3bg").addEventListener('mousemove', updateCursor)
document.getElementById("puzzle3bg").addEventListener('touchmove', updateCursor)

// I took this from someone else's codepen so I'm not sure how to modify it

解决方案

核心问题是原代码中#puzzle3bg及其伪元素层级过高,且未正确设置点击穿透属性,导致遮挡了下方圆圈的点击事件。以下是具体修改方案:

修改后的代码

HTML(结构无需调整)

<div id="puzzle3">
  <div id="puzzle3box">
    <div class="p3correctCircle"></div>
    <div class="p3correctCircle"></div>
    <div class="p3correctCircle"></div>
    <div class="p3wrongCircle"></div>
    <div class="p3wrongCircle"></div>
    <div class="p3wrongCircle"></div>
    <div class="p3wrongCircle"></div>
    <div class="p3wrongCircle"></div>
  </div>
  <div id="puzzle3bg"></div>
</div>

CSS

#puzzle3 {
  display: inline-block;
  text-align: center;
  position: relative; /* 设置为相对定位,作为内部绝对元素的容器 */
}

#puzzle3bg {
  display: block;
  width: 750px;
  height: 750px;
  --cursorX: 375px;
  --cursorY: 375px;
  position: absolute; /* 绝对定位覆盖在圆圈容器上方 */
  top: 0;
  left: 0;
  pointer-events: none; /* 允许点击穿透到下方元素 */
}

#puzzle3bg::before {
  content: "";
  display: block;
  width: 100%; /* 用百分比代替固定值,适配父容器 */
  height: 100%;
  position: absolute; /* 修改为绝对定位,确保遮罩层正确覆盖 */
  background: radial-gradient(
    circle 100px at var(--cursorX) var(--cursorY),
    rgba(170,255,255,.3) 0%,
    rgba(170,255,255,.6) 80%,
    rgba(170,255,255,1) 100%
  );
  z-index: 10;
}

#puzzle3box {
  position: relative; /* 设置相对定位 */
  z-index: 1; /* 确保圆圈容器在遮罩层下方 */
  width: 750px;
  height: 750px;
}

.p3correctCircle {
  display: inline-block;
  position: absolute;
  background: #00FF00;
  border-radius: 50%;
  width: 50px;
  height: 50px;
  transition-duration: 600ms;
  z-index: 0;
  pointer-events: auto; /* 显式允许接收点击事件 */
}

.p3wrongCircle {
  display: inline-block;
  position: absolute;
  background: #FF0000;
  border-radius: 50%;
  width: 50px;
  height: 50px;
  transition-duration: 600ms;
  z-index: 0;
  pointer-events: auto; /* 显式允许接收点击事件 */
}

JS

function updateCursor(e) {
  // 计算相对于#puzzle3的坐标,因为事件现在绑定在容器上
  const containerRect = document.getElementById("puzzle3").getBoundingClientRect();
  const x = e.clientX - containerRect.left;
  const y = e.clientY - containerRect.top;
  document.getElementById("puzzle3bg").style.setProperty('--cursorX', x + 'px')
  document.getElementById("puzzle3bg").style.setProperty('--cursorY', y + 'px')
}

// 将鼠标/触摸事件绑定到#puzzle3容器上(#puzzle3bg已设置pointer-events:none,无法触发事件)
const puzzleContainer = document.getElementById("puzzle3");
puzzleContainer.addEventListener('mousemove', updateCursor)
puzzleContainer.addEventListener('touchmove', updateCursor)

// 给圆圈添加点击事件示例
document.querySelectorAll('.p3correctCircle, .p3wrongCircle').forEach(circle => {
  circle.addEventListener('click', function() {
    console.log('点击了', this.classList.contains('p3correctCircle') ? '正确圆圈' : '错误圆圈');
    // 在这里添加你的点击逻辑
  });
});

修改关键点说明

  1. 定位调整:给#puzzle3设置position: relative,让内部绝对定位的元素以它为参考;#puzzle3bg设置position: absolute,覆盖在圆圈容器上方,实现遮罩效果。
  2. 点击穿透:给#puzzle3bg设置pointer-events: none,让它不拦截任何点击、鼠标移动等事件,点击会直接穿透到下方的圆圈元素。
  3. 事件绑定转移:因为#puzzle3bg无法再触发鼠标移动事件,所以把事件绑定到#puzzle3容器上,重新计算鼠标坐标确保手电筒位置正确。
  4. 圆圈点击权限:给圆圈显式设置pointer-events: auto,确保它们能正常接收点击事件。

内容的提问来源于stack exchange,提问作者JoshEco4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 14:19:51