【问题标题】:Clicking On-or-Through Image is Browser-Dependent单击直通图像取决于浏览器
【发布时间】:2021-01-26 23:41:04
【问题描述】:

我发现 Firefox 和 Chrome 处理在我需要修复的图像附近单击的方式有所不同。我有一个矩形,其图像约占前 65%。我保留了图像的纵横比,因此它看起来比完整的矩形更窄,这非常适合我的需要。

但是,当我在图像附近单击时,在图像两侧的边距空间中,Firefox 说我单击了矩形,而 Chrome 说我单击了图像。检查元素,我发现图像元素在两种情况下都跨越了矩形的整个宽度,但我需要的是 Firefox 中的功能(好像我正在单击“通过”这些图像边距)。

用一个例子可以更好地解释这一点。下面的代码在前 65% 中显示了一个矩形和一个窄图像。如果我在 Firefox 中单击图像的任一侧,它会说 event.target.nodeName 是“使用”(我在 <g> 中有矩形),而 Chrome 说它是“图像”。

function clickHandler(ev) {
    ev = ev || window.event;
    alert (ev.target.nodeName);
}
text {
    text-anchor: middle;
    font-size: 10px;
    font-weight: bold;
    font-family: "Times New Roman";
    pointer-events: none;
}

.m {
    stroke: dimgray;
    stroke-opacity: 1.0;
    stroke-width: 1.5;
    fill-opacity: 1.0;
    fill: white;
}
<svg id="TreeTest" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">

<defs>
    <g id="G-Box">
    <rect width="80" height="80" rx="5" ry="5"/>
    </g>
</defs>

<g id="HenryProctor">
<use tabindex="0" xlink:href="#G-Box" class="m" x="50" y="50" onclick="clickHandler(evt);">
</use>

<text x="90" y="106" dy="1em">Henry</text>
<text x="90" y="106" dy="2em">Proctor</text>

<image x="52.5" y="52.5" width="75" height="51.5" xlink:href="https://parallaxviewpoint.com/Images/Proctor_Henry_b1833.jpg" preserveAspectRatio="xMidYMin meet" onclick="clickHandler(evt);">
</image>

</g>

</svg>

有没有办法检测点击只在图像的可见部分?

[为澄清而编辑] 我需要区分单击可见图像和单击矩形中其他任何位置。我在两者上都有我的事件处理程序,但它采取的行动取决于知道用户点击了什么。

【问题讨论】:

  • 编辑器工具栏上有 [] 按钮可以在运行的 SO sn-p 中转换您的代码
  • 有趣的是,规范说图像的宽度和高度是强制性的(这没有帮助),但 Firefox 和 Chrome 似乎都忽略了这一点。如果我只指定高度,那么它似乎确实消除了那些填充边距,但图像是左对齐的。如果我能找到一种方法将其居中,那么它会起作用,但会违反规范。
  • @ACProctor the spec says no such thing。请特别参阅注释 2,其中明确指出高度和宽度是可选的。
  • 我的立场是正确的,@RobertLongson。我在developer.mozilla.org/en-US/docs/Web/SVG/Element/image 阅读了关于高度和宽度的“此属性是必需的”的注释,并认为我在规范中看到了它。我的错。
  • 我没有接受任何这些答案,因为这似乎是规范需要解决的问题。正如我在下面的另一条评论中所说,如果 CSS 指针事件有一个选项可以将真正的可见元素内容与任何扩展填充区分开来,那么它将解决这个问题。在我的特殊情况下,SVG 是由设计工具生成的,因此我能够在生成代码之前评估每个图像的纵横比,但这并不是一个真正的通用解决方案。

标签: image svg cross-browser


【解决方案1】:

这种差异是我以前没有注意到的一个有趣的怪癖。

虽然 Firefox 的行为在这种情况下似乎最有用,但我认为 Chrome 的行为更准确地遵循规范。图像每一侧的空白区域在技术上仍然是&lt;image&gt; 元素的“填充”部分。所以点击那里可能应该返回“图像”。

您是否关心用户点击的是图像的可见部分还是旁边的空白区域?如果没有,那么您可以告诉浏览器忽略 &lt;image&gt; 元素上的所有点击事件:

pointer-events="none"

现在,当您在 Chrome 中单击图像上的任意位置时,您会得到“使用”。

function clickHandler(ev) {
    ev = ev || window.event;
    alert (ev.target.nodeName);
}
text {
    text-anchor: middle;
    font-size: 10px;
    font-weight: bold;
    font-family: "Times New Roman";
    pointer-events: none;
}

.m {
    stroke: dimgray;
    stroke-opacity: 1.0;
    stroke-width: 1.5;
    fill-opacity: 1.0;
    fill: white;
}
<svg id="TreeTest" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">

<defs>
    <g id="G-Box">
    <rect width="80" height="80" rx="5" ry="5"/>
    </g>
</defs>

<g id="HenryProctor">
<use tabindex="0" xlink:href="#G-Box" class="m" x="50" y="50" onclick="clickHandler(evt);">
</use>

<text x="90" y="106" dy="1em">Henry</text>
<text x="90" y="106" dy="2em">Proctor</text>

<image x="52.5" y="52.5" width="75" height="51.5" xlink:href="https://parallaxviewpoint.com/Images/Proctor_Henry_b1833.jpg" preserveAspectRatio="xMidYMin meet" onclick="clickHandler(evt);"
       pointer-events="none">
</image>

</g>

</svg>

【讨论】:

  • 我需要区分点击可见图像和点击矩形中其他任何位置。在我的示例中,两者都有相同的事件处理程序,但它目前无法告知用户的意图。
  • Chrome 和 Firefox 对于 viewBox 的工作方式存在根本分歧。我们(Firefox)说它适用于您的内容/孩子,但不适用于元素/容器本身。 Chrome 表示它适用于元素本身。该规范不够明确,以至于两种解释都可能有效。
  • 感谢您的澄清,@RobertLongson。如果 CSS 指针事件有一个选项来区分真实可见内容和扩展填充,那么它将解决这个问题。看来我需要想出一个激进的替代方案来解决这个问题。我大部分时间都倾向于使用 Firefox,因此在向我报告之前没有意识到这种差异。
【解决方案2】:

SVG 内容在 shadowDOM 中,因此您可以使用evt.composedPath() 获取整个事件路径。

evt.composedPath()[0] 是您点击的元素。

所以 sn-ps 有一些延迟问题;在控制台中输出错误,一分钟后在附加的 SO sn-p 控制台中输出错误信息。

更新

啊! OP 想要 IE 支持(它的 2021 年,连微软都说不使用 IE)

对于那些想要使用原生 Web 组件的现代解决方案的人来说,IMG 被读取,其 naturalWidthnaturalHeight 用于从模板生成 SVG

参见 JSFiddle:https://jsfiddle.net/CustomElementsExamples/1g52eby4/

<person-card img="https://www.gravatar.com/avatar/..."></person-card>
<person-card img="https://www.gravatar.com/avatar/..."></person-card>

【讨论】:

  • 我不太明白这对丹尼有何帮助。我事先不知道图片的大小,而这个案例只是同一页面上的众多图片案例之一。图像后面已经有一个矩形(参见 G-Box 组)。
  • 我的意思是红色矩形是如何调整&lt;image&gt; 大小的指标。如果您不知道大小,则将图像加载到 IMG 中,从 onload 事件中获取其 naturalWidthnaturalHeight 并使用它来动态创建 SVG。
  • 我不认为这对我有用,丹尼。忽略 IE 不支持composedPath,一个页面上可能有数百个这样的图像,所以对所有这些图像进行计算会很慢。
  • 唉,我更新了 JSFiddle,但它是一个现代 Web 组件,可以完成所有工作,IE 不支持
  • IE 是一个 PITA,我已经努力工作了,丹尼,但我正处于将其抛在脑后的边缘。性能是更重要的问题,但我也在寻找不涉及 HTML 的解决方案,因为我还必须支持仅 SVG 选项。我很抱歉这不是问题的一部分,但我认为 SVG 可以处理这个问题。
猜你喜欢
  • 1970-01-01
  • 2012-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-13
  • 2014-01-15
  • 2015-11-22
相关资源
最近更新 更多