首页 > 解决方案 > 仅通过 svg 蒙版中的孔单击

问题描述

我有确定矩形孔的 svg 掩码。在 svg mask 后面我有一些可点击的元素,我想将事件传递给它们,但只能通过孔。我已经尝试过pointer-events值,但我只能制作整个掩码来传递事件或整个掩码来捕获它们。对于一个孔,可以使用剪辑路径简单地完成,只需确定孔的外部部分,但是几个孔会使事情变得更加困难。有没有可能避免使用剪辑路径?我也试过pointer-events: visiblePaintedand pointer-events: painted,但没有成功。

.background {
  width: 400px;
  height: 400px;
  background: red;
  cursor: pointer;
}

.svg {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
}
<button class="background">
</button>
<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg" class="svg">
  <defs>
     <mask id="mask">
       <rect
         x="0"
         y="0"
         width="400"
         height="400"
         fill="white"
       />  
       <rect
          x="20"
          y="20"
          width="40"
          height="40"
          fill="black"
       />
       <rect
          x="290"
          y="290"
          width="40"
          height="40"
          fill="black"
       />  
     </mask>
  </defs>   
  <rect
    x="0"
    y="0"
    width="400"
    height="400"
    fill="black"
    opacity="0.5"
    mask="url(#mask)"
    pointer-events="auto"
   />
</svg>

标签: javascriptcsssvgclickpointer-events

解决方案


这个问题有几个方面。首先,您是对的,蒙版和剪辑路径的行为与命中测试不同

剪辑路径是一个几何边界,给定点显然在该边界之内或之外;因此,指针事件必须在裁剪元素的渲染区域上正常捕获,但不能在裁剪区域上捕获......相比之下,掩码不是二进制转换,而是像素操作,并且完全不同的行为透明和几乎但不完全透明可能会令人困惑地任意;因此,对于应用了掩码的元素,即使在掩码变为零不透明度的区域中,仍必须捕获指针事件。

其次,剪辑路径是一种几何形状,但就像所有路径一样,它可能包含孔。<rect>您可以使用一个带有三个子路径的而不是三个<path>,只要clip-rule确保内部的子路径从周围的形状中切出即可。

第三,如果将pointer-events属性应用于<svg>HTML 上下文中的元素,它的行为会变得……奇怪。pointer-events: none元素上的任何其他值<svg>都会导致整个边界框接收事件 -为 HTML 元素提出的一种行为,但目前不属于任何规范。

这里的解决方案是pointer-events: none<svg>元素上设置,然后pointer-events: painted在子<rect>元素上反转。

button, svg {
  position:absolute;
  width:400px;
  height:400px
}
button {
  background: #0000ff;
  cursor: pointer; 
}
button:hover {
  background: #008800; 
}
svg {
  pointer-events: none;
}
.over {
  fill: #000;
  clip-path: url(#clip);
  pointer-events: painted;
}
<button></button>
<svg xmlns="http://www.w3.org/2000/svg" height="400" width="400">
 <defs>
   <clipPath id="clip" clip-rule="evenodd">
 <path d="M 20 20 h 360 v 360 h -360 z
          M 40 40 v 40 h 40 v -40 z
          M 200 290 v 40 h 40 v -40 z" />
   </clipPath>
 </defs>
 <rect y="0" x="0" height="400" width="400" class="over" />
</svg>


推荐阅读