make an html svg object also a clickable link - html
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?
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/
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
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.
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.
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.
The easiest way is to not use <object>. Instead use an <img> tag and the anchor should work just fine.
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.
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)
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>
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)
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.
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>
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>
Related
Link in custom area inside svg image does not work
I want to create some links and hover effects inside a svg image. So, I created some custom transparent areas inside one svg image, in an online images editor, in order to do that. But when I try to apply some links in those custom areas, as show below, it does not work. How can I make it work? <body> <svg> <defs></defs> <!-- custom ellipse which the link does not work --> <a href="some-link.com"> <ellipse /> </a> <!-- normal path from the svg image, which the link work --> <a href="some-link.com"> <path></path> </a> <!--rest of the image with many paths--> <path></path> </svg> </body>
The ellipse element seems to be invalid. And since the markup has an error, it might affect even the functionality of the parent element. The self-closing tag should have the slash at the end (since SVG is based on more strict XML) like below: <ellipse /> Does this change solve the problem with the link?
Scrolling to b-collapse element with <a> tag
I have an SVG element that collapes an b-collapse element when i click on it. Now i want the browser to automatically scroll down to the element that just showed up. It works with a simple tag pointing to the id of my b-collapse around the SVG element, but the problem is that the browser doesnt scroll far enough, because the b-collapse element isn't fully shown when the scrolling is triggered. Is there an easy way around this? Here is (some) of my code: <a v-for="(item, index) in items" :key="index" v-b-toggle="'collapse-'+index" v-bind:href="'#collapse-'+index"> <rect v-bind:y="y(item.box[1])" v-bind:x="x(item.box[0])" v-bind:width="(width (item.box[2], item.box[0]))" v-bind:height="(height(item.box[3], item.box[1]))" style="stroke:#00aeef;stroke-width:2;stroke-opacity:0.9;" rx="5" ry="5" ><title>{{item.category}}</title></rect></a> <b-collapse :id="'collapse-'+index" class="mt-2">...</b-collapse>
I solved it with a function and a timeout using Javascript: jumpto (index) { window.setTimeout(function () { document.getElementById(index).scrollIntoView() }, 200)
Safari, Inline SVG & <use>
I'm using SVG via the element quite extensively and it's fine in most browsers (Chrome, FF, Opera, Android Chrome and Browser). However Safari (8 Mac OSX, iOS8), in particular is having issues rendering them. The specific issue is that although the SVG seems to be occupying space in the document, nothing is actually visible. I've also tried to fill the SVG and checked several against different backgrounds to ensure that wasn't the issue. Here is an example of the "source" SVG which is just before the closing </body> and will be referenced via <use> in another part of the document. <div class="vh"> <!-- inject:svg --><svg xmlns="http://www.w3.org/2000/svg"><symbol id="youtube-icon" viewBox="0 0 512 512"><path fill="#fff" d="M129.86 50h24.736l16.933 63.55L187.264 50h24.95l-28.58 94.504v64.486H159.08v-64.486L129.86 50zm81.244 129.74c0 20.667 10.8 31.427 31.95 31.427 17.537 0 31.35-11.73 31.35-31.428v-57.49c0-18.357-13.675-31.51-31.35-31.51-19.205 0-31.95 12.692-31.95 31.51v57.49zm22.44-55.556c0-6.42 2.956-11.184 9.08-11.184 6.69 0 9.55 4.622 9.55 11.184v54.555c0 6.384-3.254 11.103-9.122 11.103-6.022 0-9.508-4.926-9.508-11.104v-54.556zm99.805-32.478v89.025c-2.658 3.33-8.57 8.784-12.822 8.784-4.666 0-5.81-3.186-5.81-7.902V91.706h-21.805v98.03c0 11.585 3.543 20.948 15.232 20.948 6.598 0 15.755-3.433 25.203-14.64v12.946h21.806V91.706H333.35zm-32.077 240.428c1.48 1.954 2.22 4.815 2.22 8.583v57.672c0 3.56-.6 6.126-1.798 7.697-2.29 2.996-7.246 2.86-10.625 1.15-1.59-.8-3.227-2.11-4.916-3.927v-69.607c1.41-1.533 2.835-2.67 4.28-3.403 3.636-1.84 8.328-1.482 10.84 1.834zm69.91-2.53c-7.696 0-9.278 5.415-9.278 13.09v11.308h18.347v-11.307c0-7.55-1.602-13.09-9.07-13.09zM434.515 412c0 27.614-22.386 50-50 50H127.484c-27.614 0-50-22.386-50-50V285.684c0-27.615 22.386-50 50-50h257.03c27.615 0 50 22.385 50 50V412zM161.734 295.128h24.195V273.15h-71.78v21.978h24.196v129.44h23.388v-129.44zm83.19 17.743h-20.768v84.786c-2.534 3.174-8.163 8.365-12.21 8.365-4.443 0-5.532-3.032-5.532-7.526V312.87h-20.768v93.36c0 22.664 15.367 22.803 26.56 16.39 4.142-2.375 8.122-5.838 11.95-10.382v12.33h20.768V312.87zm79.942 26.59c0-15.15-5.037-28-20.247-28-7.417 0-13.78 4.727-18.466 10.437V273.15h-20.97v151.418h20.97v-8.586c5.79 7.22 12.12 9.998 19.725 9.998 13.817 0 18.986-10.733 18.986-24.555V339.46zm76.758 3.44c0-20.187-9.627-32.852-29.55-32.852-18.734 0-31.543 13.463-31.543 32.853v50.137c0 20.107 10.142 34.557 29.972 34.557 21.884 0 31.122-13.034 31.122-34.557v-8.39H380.25v7.763c0 9.725-.51 15.625-9.276 15.625-8.36 0-9.07-7.246-9.07-15.625v-21.07h39.72V342.9z"></path></symbol></svg><!-- endinject --> </div> Here is the reference to that symbol within the same HTML page: <svg class="svg-icon social_links__icon" aria-labelledby="title" role="img"> <title>Twitter</title> <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#twitter-icon"></use> </svg> I have seen a similar question, however the suggested answers don't solve my problem. I have tried adding height & width to the source SVG element, the source pattern and the <svg> wrapper around the <use> and neither seems to have an impact. The class .social_links__icon on the wrapper <svg> adds the following styles: display: block; height: 24px; width: 66px; Any help is appreciated.
I have managed to find the solution to the issue and so I'm posting it here for others who may run into the same problem. My source <svg> was included at the end of the HTML document, just before the closing <body> tag and the <use> which was referencing a pattern. I tried moving it to just below the opening <body> tag and it worked. It seems that Safari won't allow a <use> to reference a subsequent part of the document. I'm not sure if this is a browser bug or not, but it's fairly simple to solve once the problem is known. I also just found an article which has the same solution.
HTML to show a SVG as a link to another page
I'm trying to show an SVG, which, when clicked, links to another page. Here is what I tried: <a href="foo.html"> <embed src="something.svg" /> </a> What is the preferred method for doing this?
Don't use the embed tag. Instead use an <img> tag and the anchor should work just fine.
Making an svg image object clickable with onclick, avoiding absolute positioning
I have tried to change the images on my site from img to svg, changing img tags to embed and object tags. But, implementing the onclick function, which previously was contained in the img tag, is proving most difficult. I found onclick had no effect when placed inside the object or embed tag. So, I made a div exclusively for the svg, and placed onclick in this div tag. But, no effect unless visitor clicks on the edges/padding of the image. I have read about overlaying a div, but am trying to avoid using absolute positioning, or specifying position at all. Is there another way to apply onclick to a svg? Has anyone encountered this problem? Questions and suggestions are welcome.
You can have an onclick event in the svg itself, I do this all the time in my work. make a rect over the space of your svg, (so define it last, remember svg uses the painters model) rect.btn { stroke:#fff; fill:#fff; fill-opacity:0; stroke-opacity:0; } then as an attribute to the rect add the onclick (this can be done with js or jquery as well). <div> <svg xmlns="http://www.w3.org/2000/svg" version="1.1"> <g> <circle ... //your img svg <rect class="btn" x="0" y="0" width="10" height="10" onclick="alert('click!')" /> </g> </svg> </div> this will work in almost all browsers: http://caniuse.com/svg
If you just use inline svg there is no problem. <svg id="svg1" xmlns="http://www.w3.org/2000/svg" style="width: 3.5in; height: 1in"> <circle id="circle1" r="30" cx="34" cy="34" onclick="circle1.style.fill='yellow';" style="fill: red; stroke: blue; stroke-width: 2"/> </svg>
This started as a comment on RGB's solution but I could not fit it in so have converted it to an answer. The inspiration for which is entirely RGB's. RGB's solution worked for me. However, I wished to note a couple of points which may help others arriving at this post (like me) who are not that familiar which SVG and who may very well have generated their SVG file from a graphics package (as I had). So to apply RGB's solutions I used: The CSS <style> rect.btn { stroke:#fff; fill:#fff; fill-opacity:0; stroke-opacity:0; } </style> The jquery script <script type="text/javascript" src="../_public/_jquery/jquery-1.7.1.js"></script> <script type="text/javascript"> $("document").ready(function(){ $(".btn").bind("click", function(event){alert("clicked svg")}); }); </script> The HTML to code the inclusion of your pre-existing SVG file in the group tag inside the SVG code. <div> <svg xmlns="http://www.w3.org/2000/svg" version="1.1"> <g> <image x="0" y="0" width="10" height="10" xlink:href="../_public/_icons/booked.svg" width="10px"/> <rect class="btn" x="0" y="0" width="10" height="10"/> </g> </svg> </div> However, in my case I have several SVG icons which I wish to be clickable and incorporating each of these into the SVG tag was starting to become cumbersome. So as an alternative approach where I could employ Classes I used jquery.svg. This is probably a shameful application of this plugin which can do all sorts of stuff with SVG's. But it worked using the following code: <script type="text/javascript" src="../_public/_jquery/jquery-1.7.1.js"></script> <script type="text/javascript" src="jquery.svg.min.js"></script> <script type="text/javascript"> $("document").ready(function(){ $(".svgload").bind("click", function(event){alert("clicked svg")}); for (var i=0; i < 99; i++) { $(".svgload:eq(" + i + ")").svg({ onLoad: function(){ var svg = $(".svgload:eq(" + i + ")").svg('get'); svg.load("../_public/_icons/booked.svg", {addTo: true, changeSize: false}); }, settings: {}} ); } }); </script> where HTML <div class="svgload" style="width: 10px; height: 10px;"></div> The advantage to my thinking is that I can use the appropriate class where ever the icons are needed and avoid quite a lot of code in the body of the HTML which aids readability. And I only need to incorporate the pre-existing SVG file once. Edit: Here is a neater version of the script courtesy of Keith Wood: using .svg's load URL setting. <script type="text/javascript" src="../_public/_jquery/jquery-1.7.1.js"></script> <script type="text/javascript" src="jquery.svg.min.js"></script> <script type="text/javascript"> $("document").ready(function(){ $('.svgload').on('click', function() { alert('clicked svg new'); }).svg({loadURL: '../_public/_icons/booked.svg'}); }); </script>
I got this working accross the latest versions of Firefox, Chrome, Safari and Opera. It relies on a transparent div before the object that has absolute position and set width and height so it covers the object tag below. Here it is, I've been a bit lazy and used inline styes: <div id="toolbar" style="width: 600px; height: 100px; position: absolute; z-index: 1;"></div> <object data="interface.svg" width="600" height="100" type="image/svg+xml"> </object> I used the following JavaScript to hook up an event to it: <script type="text/javascript"> var toolbar = document.getElementById("toolbar"); toolbar.onclick = function (e) { alert("Hello"); }; </script>
In case you're fine with wrapping the svg in another element (a for example) and putting onclick on the wrapper, svg {pointer-events: none;} CSS will do the trick.
It worked by simply replacing the <embed/> tag with <img/> and deleting the type attribute. For instance, in my code, instead of: <embed src=\"./images/info_09c.svg\" type=\"image/svg+xml\" width=\"45\" onClick='afiseaza_indicatie($i, \"$indicatii[$i]\")'> which does not answer the clicking, I wrote: <img src=\"./images/info_09c.svg\" height=\"25\" width=\"25\" onClick='afiseaza_indicatie($i, \"$indicatii[$i]\")'> It works in Internet Explorer and Google Chrome, and I hope that in the other browsers too.
You could use following code: <style> .svgwrapper { position: relative; } .svgwrapper { position: absolute; z-index: -1; } </style> <div class="svgwrapper" onClick="function();"> <object src="blah" /> </div> b3ng0 wrote similar code but it does not work. z-index of parent must be auto.
When embedding same-origin SVGs using <object>, you can access the internal contents using objectElement.contentDocument.rootElement. From there, you can easily attach event handlers (e.g. via onclick, addEventListener(), etc.) For example: var object = /* get DOM node for <object> */; var svg = object.contentDocument.rootElement; svg.addEventListener('click', function() { console.log('hooray!'); }); Note that this is not possible for cross-origin <object> elements unless you also control the <object> origin server and can set CORS headers there. For cross-origin cases without CORS headers, access to contentDocument is blocked.
Have you looked into using the CSS z-index property to make the container dev be "on top" of the svg? Because the div is (presumably) transparent, you will still see the image exactly as before. This, I believe, is the best-practice, non-hack, intended way of solving your problem. z-index is only useful for elements that have a position property of fixed, relative, or, as you've heard, absolute. However, you don't actually have to move the object. For example: <style> .svgwrapper { position: relative; z-index: 1; } </style> <div class="svgwrapper" onClick="function();"> <object src="blah" /> </div> For what it's worth, it would also be a little more elegant and safe to not use onClick at all, but instead to bind the click event using javascript. That's another issue altogether, though.
Assuming you don't need cross browser support (which is impossible without a plugin for IE), have you tried using svg as a background image? Experimental stuff for sure, but thought I would mention it.
Perhaps what you're looking for is the SVG element's pointer-events property, which you can read about at the SVG w3C working group docs. You can use CSS to set what happens to the SVG element when it is clicked, etc.
Click on SVG's <g> element in <object> with click event. Works 100%. Take a look on the nested javascript in <svg>. Don't forget to insert window.parent.location.href= if you want to redirect the parent page. https://www.tutorialspoint.com/svg/svg_interactivity.htm
I wrapped the 'svg' tag in 'a' tag and put the onClick event in the 'a' tag
I had a similar issue: it only seems that the onclick event is not occurring, but it is firing twice the svg tag had an onclick option, like: <svg ... onclick="someJsFunction() ...> it opens a dropdown menu, and had a class option named f.e. class-for-svg the path (included in the svg tag) had no any class option, in the other hand, I had a window.onclick function to close the dropdown when the user clicks on the somthing else, here the dropdown was clossing - when the object's class option matched to the svg's class option so when I clicked on the path portion inside the svg tag - the window.onclick event accurred too, and because of the does not matching(to the class name), the dropdown was clossed imediatelly, and it seems that the onclick event is not happening ) in reality it happens twise, one opens, an the second closses the drop down solution: add the same class option to the path tag too ) enjoy please )