使HTML SVG对象也成为可点击的链接

173

我在HTML页面中有一个SVG对象,并将其包装在锚点中,以便当单击SVG图像时,用户可以跳转到锚点链接。

<a href="http://www.google.com/">
    <object data="mysvg.svg" type="image/svg+xml">
        <span>Your browser doesn't support SVG images</span>
    </object>
</a>

当我使用这个代码块时,点击svg对象不能将我带到谷歌网站。在IE8以下版本中,span文本是可点击的。 我不想修改我的svg图像以包含a标签。我的问题是,如何使svg图像可点击?

1
这个单一问题导致了SVG在引入多年后仍无法得到普及。这种行为是不可想象的。 - Tyler
13个回答

264

实际上,解决这个问题的最好方法是在<object>标签上使用:

pointer-events: none;

注意:安装了广告拦截插件的用户在悬停时会在右上角看到一个类似标签的 [Block](与Flash横幅相同)。通过设置此CSS,该标签将消失。

http://jsfiddle.net/energee/UL9k9/


4
注意:IE不支持在普通元素上使用pointer-events属性,直到IE 11版本,但已经可以在SVG上支持该属性。请参考http://caniuse.com/pointer-events。 - webdesserts
10
这个解决方案(以及noelmcg的解决方案)的一个缺点是,如果您的SVG文件包含带有:hover选择器的CSS规则,则这些规则将停止工作。Ben Frain提出的解决方案没有这个问题。 - MathieuLescure
6
这应该是批准的答案。使用 img 与 SVG 结合使用会使它们无法更改内部 SVG 样式。 - cadavre
3
这应该是被批准的答案!非常好,谢谢。 - Daniel Broughan
5
很棒的回答。我在全局css中加入了这个内容,以使其通用化。object[type*="svg"]{pointer-events: none} - Gregor Macgregor
显示剩余9条评论

48

我也遇到这个问题,解决方法如下:

将对象包装在一个块元素或内联块元素中

<a>
    <span>
        <object></object>
    </span>
</a>

在添加到<a>标签中:

display: inline-block;
position: relative; 
z-index: 1;

关于 <span> 标签的使用:

display: inline-block;

并且针对 <object> 标签:

position: relative; 
z-index: -1

看这里的一个例子:http://dabblet.com/gist/d6ebc6c14bd68a4b06a6

通过这里的评论20找到的:https://bugzilla.mozilla.org/show_bug.cgi?id=294932


1
抱歉,我忘记了在对象周围包装 display: inline-block/block 元素。 - Richard
2
最佳解决方案在这里! - Baldráni
1
如果图像具有透明背景,则这些位不会显示为可点击。 - sobelito
这应该是被接受的解决方案。完美地工作并支持所有浏览器。 - Vinay Jain
我特地登录了,就是为了给这个回答点赞。 - undefined
显示剩余2条评论

36

虽然我希望能够为此贡献出一份力量,但是我在这里找到了解决方案:

https://teamtreehouse.com/forum/how-do-you-make-a-svg-clickable

将以下代码添加到锚点的CSS中:

a.svg {
  position: relative;
  display: inline-block; 
}
a.svg:after {
  content: ""; 
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left:0;
}


<a href="#" class="svg">
  <object data="random.svg" type="image/svg+xml">
    <img src="random.jpg" />
  </object>
</a>

链接在SVG和备选方案中都有效。


3
在我看来,这是最简单并且得到最多支持的解决方案。 - Type-Style
4
仍然存在一个问题:SVG指针事件(动画)不再起作用(鼠标悬停、鼠标移出、点击)!就像在对象本身上简单地使用pointer-events:none一样... - qdev
这是我在这里找到的唯一有效的解决方案。 - Jonathan E. Landrum

33
你还可以在SVG底部添加类似以下内容(就在闭合的</svg>标签之前):
<a xmlns="http://www.w3.org/2000/svg" id="anchor" xlink:href="/" xmlns:xlink="http://www.w3.org/1999/xlink" target="_top">
    <rect x="0" y="0" width="100%" height="100%" fill-opacity="0"/>
</a>

然后根据需要修改链接。我使用了100%的宽度和高度来覆盖SVG。技术的来源归功于Clearleft.com的聪明人们 - 那是我第一次看到它被使用的地方。


4
我有带:hover选择器的CSS样式嵌入到我的SVG文件中。这是唯一不会使样式失效的解决方案。 - MathieuLescure
对我有效的唯一方法-谢谢! - chewflow

27

3
谢谢,我需要将父级<a>元素的display属性设置为 block 或者 inline-block - element119
好的链接:http://www.noupe.com/inspiration/tutorials-inspiration/svg-clickable-71346.html 对每种解决方案都有优点和缺点。 - Serge Stroobandt
1
我有时也需要在某些情况下使用 inline-block,但在其他情况下似乎 block 的效果更好;我猜这取决于封闭块... - Gwyneth Llewelyn

20

最简单的方法是不要使用<object>标签。相反,使用<img>标签,然后锚点应该能够正常工作。


19
难道不是要显示一个SVG矢量图,而不是一张图片吗? - Luke
7
@ErikDahlström 但带有对SVG数据的引用的<img>标签并不总是能按照你的期望工作,即使在最新版本的Chrome中也是如此 :( http://stackoverflow.com/questions/15194870/how-can-i-get-fonts-to-work-in-svg-loaded-in-an-img-tag-in-chrome - dshap
20
如@energee所指出的,您可以使用<object>标签,并添加pointer-events: none;来使其可点击。这将保留对SVG源代码的访问,并允许您动态操纵它。 - Antoine
2
@Antoine,实际上正确的属性是“pointer-events: none;”,就像下面提到的那样,这并不起作用,谢谢你的帮助。 - godblessstrawberry
1
使用 img 并不总是可行的选择。在我的情况下,我需要操作 svg,而 img 无法很好地完成此操作,必须使用 object - Martijn
显示剩余9条评论

12

为了在所有浏览器中实现这一点,您需要结合@energee、@Richard和@Feuermurmel的方法。

<a href="" style="display: block; z-index: 1;">
    <object data="" style="z-index: -1; pointer-events: none;" />
</a>

添加:

  • pointer-events: none; 可让其在Firefox中工作。
  • display: block; 可让其在Chrome和Safari中工作。
  • z-index: 1; z-index: -1; 可让其在IE中工作。

@janaspage 我不确定...我还没有在IE 10上尝试过。如果可以的话请告诉我 :) - ChristopherStrydom
@jaepage 这并不重要,因为“object”现在将处于比其父元素更低的堆叠上下文中。 - Jason
这个在iPhone/移动设备上可以工作吗?对我来说不行。无法点击/触摸。 - bafromca

3

我尝试了这种简单干净的方法,在所有浏览器中都能工作。

在svg文件内部:

<svg>
<a id="anchor" xlink:href="http://www.google.com" target="_top">
  
<!--your graphic-->
  
</a>
</svg>
  


下面的“xlink”命名空间必须添加到SVG元素中才能使其正常工作:xmlns:xlink="http://www.w3.org/1999/xlink" - Mere Development
没有其他解决方案对我起作用,但这个确实有效,呼,谢谢! - ByteMyPixel
虽然我通常没有改变SVG文件的顾虑,但在我的情况下,我使用相同的SVG文件用于多个不同的链接 - 这意味着理论上,我必须为每个链接创建一个不同的SVG文件。当然,作为替代方案,我可以在<svg>标签中内联添加图形位,但我讨厌重复的代码(即使我实际拥有的SVG文件很小...)。 - Gwyneth Llewelyn

3
这很晚了,但我想知道为什么 energ ee's solution能够起作用:具体来说,<object>元素如何影响其父元素。

简而言之,您无法单击包含<object>元素的锚点,因为单击事件被任何在<object>元素内部的东西捕获,然后不会冒泡回来。

jsfiddle


进一步说明原问题中描述的症状:不仅是在锚点元素中包含一个<object>元素会导致锚点无法被点击,似乎任何元素中包含一个<object>元素都会导致父元素上的clickmousedownmouseup事件(可能还包括触摸事件)无法触发,(当你在<object>的边界框内点击时)
<span>
    <object type="image/svg+xml" data="https://icons.getbootstrap.com/icons/three-dots.svg">
    </object>
</span>

document
    .querySelector('span')
    .addEventListener('click', console.log) // will not fire

现在,<object>元素的行为有点像<iframe>,因为它们将建立新的浏览上下文,包括内容是<svg>文档时。在JavaScript中,这通过存在HTMLObjectElement.contentDocumentHTMLObjectElement.contentWindow属性来体现。
这意味着,如果您向<object>内部的<svg>元素添加事件监听器:
document
    .querySelector('object')
    .contentDocument  // returns null if cross-origin: the same-origin policy
    .querySelector('svg')
    .addEventListener('click', console.log)

然后点击图片,您将看到事件被触发。
这时就很清楚为什么 pointer-events: none; 解决方案可行:
- 如果没有这个样式,任何被视为“交互性”的 MouseEvent(例如 clickmousedown,但不包括 mouseenter)都会被发送到嵌套的浏览上下文中的 <object> 内部,它永远不会冒泡出来。 - 有了这个样式,MouseEvent 就不会首先被发送到 <object> 中,然后 <object> 的父元素将像往常一样接收事件。 这也解释了为什么 z-index 解决方案是可行的:只要您能够防止将 click 事件发送到嵌套的文档中,单击操作就应该按预期工作。
在我的测试中,只要父元素不是 inline,并且 <object> 元素被定位且具有负的 z-indexz-index 解决方案就可以起作用。
另外,您可以找到一种方法将事件传播回来。
let objectElem = document.querySelector('object')
let svgElemt = objectElem.contentDocument.querySelector('svg')

svgElem.addEventListener('click', () => {
    window.postMessage('Take this click event please.')
    // window being the outermost window
})

window.addEventListener('message', console.log)

3
我通过编辑svg文件解决了这个问题。
我将整个svg图形的xml代码包装在一个组标签内,该组标签具有以下点击事件:
<svg .....>
<g id="thefix" onclick="window.top.location.href='http://www.google.com/';">
 <!-- ... your graphics ... -->
</g>
</svg>

解决方案在所有支持对象SVG脚本的浏览器中都有效。(默认情况下,在你的对象元素中使用a img标签可以覆盖不支持SVG的浏览器,并覆盖所有浏览器)

你是否发现将onclick添加到外部的<svg>元素而不进行任何包装并没有起作用? - Robert Longson
1
您也可以使用根SVG元素的事件。除了onclick事件外,我还使用onmouseout、ontouchstart、ontouchend等事件...至于根SVG元素,我经常使用onload事件。Ben Frain的解决方案涉及绘制额外的覆盖对象(矩形)以捕获单击事件...因此,我提供了这个解决方案,显示在绘图元素本身上获取事件,而无需制作透明覆盖层来获取单击事件。当您不想绘制另一个元素或者您想要与现有形状特定的事件而不是矩形时,这将非常有帮助。 - Bruce Pezzlo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接