Html – How to make an SVG image with hover effect inside clickable

csshtmlsvg

Imagine we have an anchor containing an SVG icon with a hover effect and some text.

Let's assume the icon is ment to be used multiple times in various links pointing to different URLs.

  • the SVG should be in a separate file not inline
  • the link shouldn't be embeded inside the SVG file
  • the hover effect should work
  • JS and noscript fallback to PNG is fair game

Ways to embed SVG

object:

<a href="http://tomasreichmann.cz/" >
    <object data="http://svgtest.tomasreichmann.cz/images/grafika.svg" type="image/svg+xml">
    </object>
    Link
</a>

image

<a href="http://tomasreichmann.cz/" >
    <img src="http://svgtest.tomasreichmann.cz/images/grafika.svg" alt="" />
    Link
</a>

Demo
http://jsfiddle.net/YZkj9/

Is this really impossible to achieve?
Is this the reason nobody uses SVGs even though it's supported since IE9?

Thank you for your time and effort, you guys are great!

Best Answer

SVG's can in fact be manipulated with javascript. The catch, is that SVG objects are very buggy when attempting to be selected with jQuery, so you have to use regular javascript in making your selections at least.

Let's say (like in my case) you wrap your object in a div and an href tag; it's going to look something like this:

<div id="mp3-link">
  <a href="http://your-url.com">
    <object type="image/svg+xml" class="mp3-svg" id="object-svg" data="your-svg-url.com"></object>
  </a>
</div>

And the code that the object tag is going to spit out is going to look something like this (in my case, an MP3 downloads link).

<div id="mp3-link">
<a href="http://google.com">
<object type="image/svg+xml" class="mp3-svg" id="object-svg">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 612 792" style="enable-background:new 0 0 612 792;" xml:space="preserve">
    <defs>
    <style type="text/css"><![CDATA[
        .fill-blue {
            fill:inherit;
            stroke-width:0;
        }
        .mp3 {
            font-family:'Lato-Bold'; 
            stroke-width:0;
        }
        .stroke-blue {
            fill-opacity:0;
            stroke:inherit;
            stroke-width:inherit;
            stroke-miterlimit:inherit;
        }
        #hover-me:hover {
            stroke:#3c4147;
            fill:#3c4147;
        }
        #hover-me {
            stroke:#227AA5;
            stroke-width:22;
            stroke-miterlimit:10;
            fill:#227AA5;
        }
    ]]></style>
</defs>
<g id="hover-me">
<text transform="matrix(0.7813 0 0 1 216.4761 524.5479)" class="mp3 fill-blue hover-me" style="font-size:193.4593;">MP3</text>
<path class="stroke-blue hover-me" d="M377.1,560.5v79 c0,6.2-5,11.2-11.2,11.2H30.6c-6.2,0-11.2-5-11.2-11.2V153.1c0-6.2,5-11.2,11.2-11.2h235.2c6.2,0,111.3,121.2,111.3,121.2v80.7  M593.7,535.4V373.5c0-11-9-20-20-20H189.2c-11,0-20,9-20,20v161.8c0,11,9,20,20,20h384.6C584.7,555.4,593.7,546.4,593.7,535.4z"/>
<path class="page-flap fill-blue hover-me" d="M272,164.5l46.3,50.4l46.7,52.6v2.4h-93V164.5 M267,131h-18v145.1c0,9.4,7.7,17,17.2,17H388v-34.2   l-52.6-59.3l-53.9-58.7L267,131L267,131z"/>
</g>
</svg>

</object>
</a>
</div>

What we need to do, is select an inner element of the svg (in this case, "#hover-me") and attach a javascript function to it:

//this is important, as the svg tends to load a little later than the rest of the elements
window.onload=function() {

    // Get the Object by ID
    var theObject = document.getElementById("object-svg");
    // Get the SVG document inside the Object tag
    var svgDoc = theObject.contentDocument;
    // Get one of the SVG items by ID;
    var svgItem = svgDoc.getElementById("hover-me");

    //our javascript selector
    svgItem.addEventListener('click', function() { 
    //here, I'm using jQuery to select the parent and get the href. This is so you can see that jQuery is possible, just not for the selection portion of the code
    var svgHref = $(theObject).parent().attr("href");
    //now, we navigate to the external href. I chose to open in new window.
    var win = window.open(svgHref, '_blank');
    win.focus();
  });
}; //window.onload

So now, we've created a function that will find the link that wraps the object using javascript, and then it will navigate the user to that link using jQuery.

I tried to attach a jsfiddle, but jsfiddle's don't allow you to import an object so you'll have to try this code out on an actual web page

More info in selecting SVG elements with javascript

Edit

After looking into this further, I came up with an even more optimized way to do this:

By using javascript to actually change the styling of the hover, we can then allow the svg image to operate like a normal link (right click options, status window in the lower corner, etc)

So in this case using the same svg markup and adding a class to our link

<div id="mp3-link">
  //we'll call our link "a-svg"
  <a href="http://your-url.com" class="a-svg">
<object type="image/svg+xml" class="mp3-svg" id="object-svg" data="your-svg-url.com"></object>
  </a>
</div>

We can use this code to change the styling of the svg when the link is hovered:

window.onload=function() {
//get our link
var theA = document.getElementsByClassName("a-svg");
//loop through all of these (jQuery does this by default, but we're forced to use regular javascript
for(var i=0;i<theA.length;i++){
    //when the user hovers over the link...
    theA[i].addEventListener('mouseover', function() { 
    var thisObject = this.getElementsByClassName('mp3-svg')[0];
    var svgDoc = thisObject.contentDocument;
    // Get one of the SVG items by ID;
    var svgItem = svgDoc.getElementById("hover-me");
    //change the attributes of the svg
    svgItem.setAttribute("fill", "#3c4147");
    svgItem.setAttribute("stroke", "#3c4147");
});
//now revert the changes when the mouse leaves
theA[i].addEventListener('mouseleave', function() { 
    var thisObject = this.getElementsByClassName('mp3-svg')[0];
    var svgDoc = thisObject.contentDocument;
    // Get one of the SVG items by ID;
    var svgItem = svgDoc.getElementById("hover-me");
    svgItem.setAttribute("fill", "#227aa5");
    svgItem.setAttribute("stroke", "#227aa5");
});
}   
};

Lastly, we'll need a little css in order to make it so that the link is on top of the svg

.a-svg:after {
  top:0;
  bottom:0;
  left:0;
  right:0;
  position:absolute;
  content"";
}
#mp3-link {
  position:relative;
  height:140px;
  width:140px;
}

Now we have a fully functional link with a hover capability for our svg image.