make an html svg object also a clickable link
Asked Answered
S

13

173

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?

Sperrylite answered 7/7, 2012 at 10:5 Comment(1)
This single issue is responsible for SVG not picking up years after its introduction. This kind of behavior is unthinkable.Blakemore
D
269

Actually, the best way to solve this is... on the <object> 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/

Dyaus answered 16/6, 2013 at 13:22 Comment(11)
Note: IE won't support pointer-events on regular elements until IE 11, but already does support them on SVG. See caniuse.com/pointer-eventsTilton
Works perfectly, thank you. Just for future reference, I was using a jQuery Click event on an element, it was only working on the padding until I added the above CSS on the object tag.Viridity
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.Johppa
This should be approved answer. Using img with svg makes then unusable for changing internal SVG styles.Audacity
Great answer. I made mine universal with this in the global css. object[type*="svg"]{pointer-events: none}Tuinenga
the svg seems to disappear in chrome 48 and opera 35 (clearly visible when replacing the fallback-image by some text...), but works fine in firefox and safari... Anyone who would know why?Pecan
SVG inline hover style won't work. Any solution that allow both SVG propagate click event and Inline hover styleMaillot
@Maillot what do you mean by "inline hover style"? Inline styles, like <element style="inline-style: rule;">, don't support hover statesAnthracnose
This is the real answer. The solution with the img tag doesn't work at all in my case as no image is displayed. In my case I wanted the object tag to be clickable for JS click event and this also solves that problem.Daveen
This will disable the animation of the SVGSuckle
Doesn't work if you only have the svg image available. Does maybe solve the problem in this particular case. But only because you have the image as a png as well.Billen
F
48

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

Frescobaldi answered 4/10, 2012 at 16:51 Comment(7)
Apologies, forgot the display: inline-block/block element to wrap around the objectFrescobaldi
Best solution here !Epigeous
this is best solution for this problem and works on all browserRawlins
if image has transparent bg then those bits do not appear clickableSupranatural
This worked for me, I also had to add height: 100% to the a and span elements in my situationTonina
This should be the accepted solution. Works perfectly and supports all browsers.Malediction
man I logged in, specially to upvote this answer.Presnell
D
36

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.

Dibbrun answered 2/8, 2013 at 13:40 Comment(3)
This is the easiest and most supported solution in opinionBellyache
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 ...Perjured
This was the only solution here that worked for meHussey
P
33

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.

Perfecto answered 23/10, 2013 at 22:30 Comment(2)
I have css styles with a :hover selector embedded in my SVG file. This is the only solution which doesn't deactivate the style.Johppa
The only thing that worked for me - thanks!Tatiania
S
27

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.

Schilt answered 25/7, 2013 at 10:46 Comment(3)
Thanks, I needed the display set to block or inline-block on the parent <a>.Breastbeating
Good link: noupe.com/inspiration/tutorials-inspiration/… has pros and cons for each solution.Malissamalissia
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...Kitchenette
D
20

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

Dancette answered 7/7, 2012 at 10:59 Comment(14)
This works. My main issue with this is it's harder to make an IE fallback, but using the alt tag is good enough.Sperrylite
The img tag would normally go where the span tag is for this to degrade gracefully.Junkman
Isn't the idea to display an svg vector, not an image?Duna
@luke: The svg is vector data, the img tag is just a way to reference it, it is then up to the browser to render the svg properly (read: non-pixelated). All the information is there for rendering properly at any resolution.Kantos
@ErikDahlström but <img> with a reference to svg data doesn't always work as you expect, even in the latest version of Chrome :( #15195370Sideline
@PsychoDad svg in img works just fine in IE9 and up, see examples here: xn--dahlstrm-t4a.net/svg/htmlKantos
It does you are right, the problem I was seeing was if you try and specify a width and height that do not maintain the aspect ratio, ie does some funny stuff. That's what I was seeing. Now that I have the aspect ratio correct, it works fine.Febrific
As @Dyaus 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.Randa
@Randa actually correct property is 'pointer-events: none;' like mentioned below, this doesn't work, thank you thoughPyroxylin
Using a img isn't always an option. In my case, I need to manipulate the svg, which can;t be properly done via img, I have to use object.Excitement
this does not answer the question askedFuthark
This does not answer the question and does not solve the problem if I need to use an object elementKnossos
@Antoine, disabling pointer events also disables svg animation (like hover).Wire
SVG image which contain script for complex drawing, will NOT work in <img>Laris
I
12

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.
Izawa answered 6/8, 2014 at 16:10 Comment(3)
@janaspage I'm not sure... I haven't tried it out on IE 10. Let me know if it works :)Izawa
@jaepage It shouldn't matter, because object will now be in a lower stacking-context (under) than it's parent.Gunning
does this work on an iPhone/mobile? doesn't for me. not clickable/tappableNadanadab
H
3

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)

Holdall answered 14/7, 2014 at 9:42 Comment(2)
Did you find that adding the onclick to the outer <svg> element and not wrapping it at all didn't work?Feudist
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.Holdall
E
3

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

<svg>
<a id="anchor" xlink:href="http://www.google.com" target="_top">
  
<!--your graphic-->
  
</a>
</svg>
  
Eusebiaeusebio answered 19/8, 2015 at 10:25 Comment(3)
The following 'xlink' namespace will have to be added to the svg element to make this work: xmlns:xlink="w3.org/1999/xlink"Musselman
None of the other solutions worked for me but this one did, whew, thank you!Lookin
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 <svg> tag, but I hate duplicate code (even though the actual SVG I've got is small...)Kitchenette
L
3

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 <object> element in it because the click events are being captured by whatever is inside of the <object> 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 <object>, which will never bubble out of it.

  • With this style, the MouseEvents aren't sent into the <object> in the first place, then the <object>'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)
Lucianolucias answered 15/1, 2021 at 7:8 Comment(0)
L
1

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.

Lahnda answered 10/5, 2021 at 16:50 Comment(0)
H
0

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>
Hoogh answered 4/6, 2020 at 14:32 Comment(1)
btw I am using tailwind css.Hoogh
L
-5

Do it with javascript and add a onClick-attribute to your object-element:

<object data="mysvg.svg" type="image/svg+xml" onClick="window.location.href='http://google.at';">
    <span>Your browser doesn't support SVG images</span>
</object>
Lenhart answered 7/7, 2012 at 10:8 Comment(3)
I tried this, both with and without the surrounding <a> tags, and I cannot get this to work. I tried in FF and Chrome on Linux. Which browser did you try this in?Sperrylite
It would be great if you could try it and confirm that it works so others who read this can be confident of your answer. "It must work" is fine in theory, but for me it must work in practice.Sperrylite
I just tried this on Chrome 45 on Windows and it seems to work fine. I added onClick directly to an SVG tag without a wrapping anchor. It would be nice if the downvotes explained why.Conjurer

© 2022 - 2024 — McMap. All rights reserved.