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?

iancoleman
  • 2,766
  • 2
  • 19
  • 17
  • 1
    This single issue is responsible for SVG not picking up years after its introduction. This kind of behavior is unthinkable. – Tyler Jun 16 '22 at 08:35

13 Answers13

262

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/

Martijn
  • 15,791
  • 4
  • 36
  • 68
energee
  • 2,763
  • 2
  • 14
  • 13
  • 4
    Note: IE won't support pointer-events on regular elements until IE 11, but already does support them on SVG. See http://caniuse.com/pointer-events – webdesserts Oct 13 '13 at 02:11
  • 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. – JDavies Jul 29 '14 at 15:59
  • 10
    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. – MathieuLescure Apr 14 '15 at 15:08
  • 6
    This should be approved answer. Using `img` with svg makes then unusable for changing internal SVG styles. – cadavre Apr 17 '15 at 15:26
  • 5
    Great answer. I made mine universal with this in the global css. object[type*="svg"]{pointer-events: none} – Gregor Macgregor Feb 29 '16 at 21:43
  • 2
    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? – Mr Tsjolder from codidact Mar 02 '16 at 14:16
  • SVG inline hover style won't work. Any solution that allow both SVG propagate click event and Inline hover style – tryer3000 Aug 22 '16 at 06:59
  • @tryer3000 what do you mean by "inline hover style"? Inline styles, like ``, don't support hover states – henry Aug 08 '17 at 18:29
  • 1
    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. – beginner_ Jun 21 '18 at 05:19
  • This will disable the animation of the SVG – Thach Lockevn Jul 31 '20 at 11:08
  • 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. – Sammeeey Jul 10 '23 at 12:38
47

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

mixel
  • 25,177
  • 13
  • 126
  • 165
Richard
  • 476
  • 4
  • 6
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.

noelmcg
  • 1,057
  • 3
  • 21
  • 44
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.

Mo.
  • 26,306
  • 36
  • 159
  • 225
Ben Frain
  • 2,510
  • 1
  • 29
  • 44
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.

Silvan
  • 156
  • 3
  • 13
Feuermurmel
  • 9,490
  • 10
  • 60
  • 90
20

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

Erik Dahlström
  • 59,452
  • 12
  • 120
  • 139
  • This works. My main issue with this is it's harder to make an IE fallback, but using the alt tag is good enough. – iancoleman Jul 07 '12 at 11:10
  • 1
    The img tag would normally go where the span tag is for this to degrade gracefully. – Adrian Garner Oct 08 '12 at 02:26
  • 19
    Isn't the idea to display an svg vector, not an image? – Luke Dec 02 '12 at 23:24
  • @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. – Erik Dahlström Dec 03 '12 at 08:02
  • 7
    @ErikDahlström but `` with a reference to svg data doesn't always work as you expect, even in the latest version of Chrome :( http://stackoverflow.com/questions/15194870/how-can-i-get-fonts-to-work-in-svg-loaded-in-an-img-tag-in-chrome – dshap Mar 07 '13 at 03:18
  • @PsychoDad svg in img works just fine in IE9 and up, see examples here: http://xn--dahlstrm-t4a.net/svg/html/ – Erik Dahlström Jul 12 '13 at 08:35
  • 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. – jjxtra Jul 12 '13 at 16:49
  • 20
    As @energee pointed it out, you can use `` 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 Jul 28 '14 at 12:56
  • 2
    @Antoine actually correct property is 'pointer-events: none;' like mentioned below, this doesn't work, thank you though – godblessstrawberry Apr 29 '15 at 07:30
  • 1
    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`. – Martijn May 17 '16 at 14:16
  • 1
    this does not answer the question asked – Omar May 16 '18 at 22:12
  • 1
    This does not answer the question and does not solve the problem if I _need_ to use an object element – Channel May 17 '18 at 15:34
  • @Antoine, disabling pointer events also disables svg animation (like hover). – brgs Jul 03 '19 at 11:26
  • SVG image which contain script for complex drawing, will NOT work in – Xerix Sep 09 '20 at 07:20
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.
ChristopherStrydom
  • 7,338
  • 5
  • 21
  • 34
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)

  • Did you find that adding the onclick to the outer `` element and not wrapping it at all didn't work? – Robert Longson Jul 15 '14 at 11:09
  • 1
    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. – Bruce Pezzlo Jul 24 '14 at 00:31
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>
  
  • The following 'xlink' namespace will have to be added to the svg element to make this work: xmlns:xlink="http://www.w3.org/1999/xlink" – Mere Development Oct 05 '15 at 14:21
  • None of the other solutions worked for me but this one did, whew, thank you! – ByteMyPixel Sep 30 '16 at 18:16
  • 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...) – Gwyneth Llewelyn May 12 '20 at 00:13
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)
tonywu7
  • 113
  • 1
  • 5
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.

Rostasan
  • 57
  • 9
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>
Ege Hurturk
  • 693
  • 1
  • 10
  • 12
-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>
Stefan Fandler
  • 1,141
  • 7
  • 13