ChatGPT解决这个技术问题 Extra ChatGPT

make an html svg object also a clickable link

I have an SVG object in my HTML page and am wrapping it in an anchor so when the svg image is clicked it takes the user to the anchor link.

<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>

When I use this code block, clicking the svg object doesn't take me to google. In IE8< the span text is clickable.

I do not want to modify my svg image to contain tags.

My question is, how can I make the svg image clickable?

This single issue is responsible for SVG not picking up years after its introduction. This kind of behavior is unthinkable.

M
Martijn

Actually, the best way to solve this is... on the tag, use:

pointer-events: none;

Note: Users which have the Ad Blocker plugin installed get a tab-like [Block] at the upper right corner upon hovering (the same as a flash banner gets). By settings this css, that'll go away as well.

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


Note: IE won't support pointer-events on regular elements until IE 11, but already does support them on SVG. See caniuse.com/pointer-events
A drawback of this solution (and the one from noelmcg as well) is if your SVG file contains CSS rules with a :hover selector, these rules will stop working. The solution proposed by Ben Frain doesn't have this problem.
This should be approved answer. Using img with svg makes then unusable for changing internal SVG styles.
This needs to be the approved answer! Really nice, thanks
Great answer. I made mine universal with this in the global css. object[type*="svg"]{pointer-events: none}
m
mixel

I had the same issue and managed to solve this by:

Wrapping the object with an element set to block or inline-block

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

Adding to <a> tag:

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

and to the <span> tag:

display: inline-block;

and to the <object> tag:

position: relative; 
z-index: -1

See an example here: http://dabblet.com/gist/d6ebc6c14bd68a4b06a6

Found via comment 20 here https://bugzilla.mozilla.org/show_bug.cgi?id=294932


Apologies, forgot the display: inline-block/block element to wrap around the object
Best solution here !
this is best solution for this problem and works on all browser
if image has transparent bg then those bits do not appear clickable
This worked for me, I also had to add height: 100% to the a and span elements in my situation
n
noelmcg

Would like to take credit for this but I found a solution here:

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

add the following to the css for the anchor:

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>

Link works on the svg and on the fallback.


This is the easiest and most supported solution in opinion
this still has an issue: SVG pointer events (animations) are not working anymore (mouseover, mouseout, click) ! Just like simply using pointer-events: none on the object itself ...
This was the only solution here that worked for me
M
Mo.

You could also stick something like this in the bottom of your SVG (right before the closing </svg> tag):

<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>

Then just amend the link to suit. I have used 100% width and height to cover the SVG it sits in. Credit for the technique goes to the smart folks at Clearleft.com - that's where I first saw it used.


I have css styles with a :hover selector embedded in my SVG file. This is the only solution which doesn't deactivate the style.
The only thing that worked for me - thanks!
S
Silvan

A simplification of Richard's solution. Works at least in Firefox, Safari and Opera:

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

See http://www.noupe.com/tutorial/svg-clickable-71346.html for additional solutions.


Thanks, I needed the display set to block or inline-block on the parent <a>.
Good link: noupe.com/inspiration/tutorials-inspiration/… has pros and cons for each solution.
I also needed to use inline-block in some cases, but block seemed to work well on other cases; I guess it depends on the enclosing blocks...
E
Erik Dahlström

The easiest way is to not use . Instead use an tag and the anchor should work just fine.


The img tag would normally go where the span tag is for this to degrade gracefully.
Isn't the idea to display an svg vector, not an image?
@ErikDahlström but <img> with a reference to svg data doesn't always work as you expect, even in the latest version of Chrome :( stackoverflow.com/questions/15194870/…
As @energee pointed it out, you can use <object> tag and add a point-event: none; to make it clickable. It preserve access to your svg source code and allow you to dynamically manipulate it.
@Antoine actually correct property is 'pointer-events: none;' like mentioned below, this doesn't work, thank you though
C
ChristopherStrydom

To accomplish this in all browsers you need to use a combination of @energee, @Richard and @Feuermurmel methods.

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

Adding:

pointer-events: none; makes it work in Firefox.

display: block; gets it working in Chrome, and Safari.

z-index: 1; z-index: -1; makes it work in IE as well.


@janaspage I'm not sure... I haven't tried it out on IE 10. Let me know if it works :)
@jaepage It shouldn't matter, because object will now be in a lower stacking-context (under) than it's parent.
does this work on an iPhone/mobile? doesn't for me. not clickable/tappable
B
Bruce Pezzlo

I resolved this by editing the svg file too.

I wrapped the xml of the whole svg graphic in a group tag that has a click event as follows:

<svg .....>
<g id="thefix" onclick="window.top.location.href='http://www.google.com/';">
 <!-- ... your graphics ... -->
</g>
</svg>

Solution works in all browsers that support object svg script. (default a img tag inside your object element for browsers that don't support svg and you'll cover the gamut of browsers)


Did you find that adding the onclick to the outer <svg> element and not wrapping it at all didn't work?
You can use the root svg element's events as well. in addition to onclick events I use onmouseout, ontouchstart , ontouchend etc... and as for root svg element i use the onload event frequently. Ben Frain solution below involves drawing an extra cover object (a rectangle ) to capture the click events ... so I offered up this solution showing getting events on the drawing elements themselves without having to make a transparent cover just to get a click event. Especially helpful when you don't want to draw another element or you want the events specific to existing shape and not a rectangle.
D
Dario Rigon

i tried this clean easy method and seems to work in all browsers. Inside the svg file:


The following 'xlink' namespace will have to be added to the svg element to make this work: xmlns:xlink="w3.org/1999/xlink"
None of the other solutions worked for me but this one did, whew, thank you!
Although I usually have no qualms about changing an SVG file directly, in my scenario, I use the same SVG for several different links — meaning that theoretically, I'd have to create a different SVG for each. Alternatively, of course, I could add the graphic bit inline in the tag, but I hate duplicate code (even though the actual SVG I've got is small...)
T
Tony Wu

This is very late, but I was wondering why energee's solution works: specifically, how the <object> element affects its parent elements.

tl;dr You cannot click on an anchor that has an element in it because the click events are being captured by whatever is inside of the element, which then doesn't bubble it back out.

jsfiddle

To expand on the symptom described in the original question: not only will an <object> element inside an anchor element cause the anchor to become unclickable, it seems that an <object> element as a child of any element will cause click, mousedown, and mouseup events (possibly touch events too) to not fire on the parent element, (when you are clicking inside the <object>'s bounding rect.)

<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

Now, <object> elements behave somewhat "like" <iframe>s, in the sense that they will establish new browsing contexts, including when the content is an <svg> document. In JavaScript, this is manifested through the existence of the HTMLObjectElement.contentDocument and HTMLObjectElement.contentWindow properties.

This means that if you add an event listener to the <svg> element inside the <object>:

document
    .querySelector('object')
    .contentDocument  // returns null if cross-origin: the same-origin policy
    .querySelector('svg')
    .addEventListener('click', console.log)

and then click on the image, you will see the events being fired.

Then it becomes clear why the pointer-events: none; solution works:

Without this style, any MouseEvent that is considered "interactive" (such as click and mousedown, but not mouseenter) is sent to the nested browsing context inside the , which will never bubble out of it.

With this style, the MouseEvents aren't sent into the in the first place, then the 's parent elements will receive the events as usual.

This should explain the z-index solution as well: as long as you can prevent click events from being sent to the nested document, the clicking should work as expected.

(In my test, the z-index solution will work as long as the parent element is not inline and the <object> is positioned and has a negative z-index)

(Alternatively, you can find a way to bubble the event back up):

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)

R
Rostasan

I was using simply

        <a href="#">
            <img src="../../assets/images/logo.svg" alt="">
        </a>

Which works fine except I was trying to apply a :hover state. What brought me here was when I used

        <a href="#">
            <object data="../../assets/images/logo.svg" type="image/svg+xml" class="logo">
            </object>
        </a>

I lost my link and noticed in DevTools that the link still appeared around the SVG, but the :hover state worked. Utilizing energee's elegant answer, my link worked, but of course I lost the :hover. So it looks like the object tag isn't a great solution for applying a :hover change to an SVG.

I am curious, why would you not use the img tag to display an SVG without anything special added to it, like :hover? Using the img tag also works with the a tag.


E
Ege Hurturk

Just don't use <object>. Here's a solution that worked for me with <a> and <svg> tags:

<a href="<your-link>" class="mr-5 p-1 border-2 border-transparent text-gray-400 rounded-full hover:text-white focus:outline-none focus:text-white focus:bg-red-700 transition duration-150 ease-in-out" aria-label="Notifications">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="30" 
    height="30"><path class="heroicon-ui" fill="#fff" d="M17 16a3 3 0 1 1-2.83 
    2H9.83a3 3 0 1 1-5.62-.1A3 3 0 0 1 5 12V4H3a1 1 0 1 1 0-2h3a1 1 0 0 1 1 
    1v1h14a1 1 0 0 1 .9 1.45l-4 8a1 1 0 0 1-.9.55H5a1 1 0 0 0 0 2h12zM7 12h9.38l3- 
   6H7v6zm0 8a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm10 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/>
    </svg>
</a>

btw I am using tailwind css.