仅单击SVG蒙版中的孔 [英] Click only through holes in svg mask
问题描述
我有svg遮罩,可确定矩形中的孔.在svg mask后面,我有一些可单击的元素,我想将事件传递给它们,但只能通过孔.我已经尝试过使用pointer-events
值,但是我只能使整个掩码都可以传递事件,或者使整个掩码都可以捕获事件.对于一个孔,可以简单地使用剪切路径完成,只需确定孔的外部即可,但是几个孔会使事情变得更加困难.是否有可能避免使用剪切路径?我也尝试了pointer-events: visiblePainted
和pointer-events: painted
,但是没有成功.
I have svg mask which determines holes in rectangular. Behind svg mask I have some clickable elements and I would like to pass events to them, but only through holes. I've experimented with pointer-events
values, but I can only make either whole mask to pass events or whole mask to capture them. For one hole it can be simply done using clip-path, just determining outer part of the hole, but several holes make things more difficult. Is there any possibility to avoid using clip-path? I also tried pointer-events: visiblePainted
and pointer-events: painted
, but had no success.
.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>
推荐答案
此问题有多个方面.首先,没错,掩码和剪切路径的行为是不同与点击测试有关.
There are several aspects to this problem. First, you are right the behavior of masks and clip-paths is different in relation to hit-testing.
剪切路径是几何边界,给定点显然在该边界的内部或外部;因此,指针事件必须正常地在裁剪元素的渲染区域上捕获,但一定不能在裁剪区域上捕获...相比之下,遮罩不是二进制转换,而是像素操作,以及完全不同的行为透明但几乎不完全透明可能是令人困惑的任意性;因此,对于应用了蒙版的元素,即使在蒙版的透明度变为零的区域,也必须捕获指针事件.
A clip path is a geometric boundary, and a given point is clearly either inside or outside that boundary; thus, pointer events must be captured normally over the rendered areas of a clipped element, but must not be captured over the clipped areas... By contrast, a mask is not a binary transition, but a pixel operation, and different behavior for fully transparent and almost-but-not-fully-transparent may be confusingly arbitrary; as a consequence, for elements with a mask applied, pointer events must still be captured even in areas where the mask goes to zero opacity.
第二,剪切路径是一种几何形状,但是就像所有路径一样,它可能包含孔.代替三个<rect>
,您可以将一个<path>
与三个子路径一起使用,只要
Second, a clip-path is a geometric shape, but just like all paths, it might contain holes. Instead of three <rect>
s, you can use one <path>
with three subpaths, as long as the clip-rule
makes sure the subpaths inside get cut out of the surrounding shape.
第三,如果将pointer-events
属性应用于HTML上下文中的<svg>
元素,则其行为会变得...奇怪. <svg>
元素上除pointer-events: none
之外的任何其他值都将导致整个边界框接收事件-行为针对HTML元素提出的建议,但目前不属于任何规范.
Third, if the pointer-events
property is applied to an <svg>
element in a HTML context, its behavior becomes...strange. Any other value than pointer-events: none
on the <svg>
element lead to the whole bounding box receiving events - a behavior proposed for HTML elements, but currently not part of any spec.
这里的解决方案是在<svg>
元素上设置pointer-events: none
,然后在子<rect>
元素上用pointer-events: painted
反转.
The solution here is to set pointer-events: none
on the <svg>
element, and then to reverse that with pointer-events: painted
on the child <rect>
element.
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>
这篇关于仅单击SVG蒙版中的孔的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!