Mouseover effects in SVGs

In this tutorial I'll describe five different methods to achieve a mouseover effect in an SVG. I'll start with the simplest and most limited approach (CSS), and work up to the most complex, but most flexible approach (Javascript/ECMAScript, which is described in more detail here). To view the full code for any of examples in this post, right click on an image and chose View Frame Source or something similar, depending on your browser.

For further information see:

Example SVG

SVGs seem to be an increasingly popular way of adding high quality, interactive images to the web. Even IE9 now supports SVGs to a degree. Older IE users will have to use a Chrome Frame or something similar. Note, that I've tested only these effects in Chrome and Firefox. In order to demonstrate mouseover effects, we need a simple SVG. The code below draws two squares: one blue, one green.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="300" height="80">

  <text x="10" y="35">Two passive squares:</text>

  <rect id="rect1"  x="160" y="10" 
   width="60" height="60" fill="blue"/>

  <rect id="rect2" x="230" y="10"
   width="60" height="60" fill="green"/>

</svg>

CSS

The simplest way to get a mouseover effect is to use the hover effect with CSS styling. Note that the style element can be written within the SVG itself and works just as with HTML. For example, add the following code into the <svg> element:

  <style>
    rect:hover
    {
      opacity: 0.5;
    }
  </style>

CSS within SVG works just as with HTML, so we can get more specific effects by using different selectors. For example, using .some-class-name:hover allows us to selectively apply the mouseover effect to only those elements with the attribute class="some-class-name".

If you can get away with just using CSS, I'd recommend it, but there are some limitations:

  • We can only effect the properties of the element we have moused-over (although we can partially get around this using groups and more advanced CSS selectors).
  • We can only effect the style of an element, not its other attributes such as size or position.
  • We can only trigger events with a mouse hover, and not, for example, on a mouse click.

Onmouseover events

A more targeted approach is to add a function directly into the <rect> element. The function onmouseover is called when the mouse is moved over an element, and we can set this to changes the element's opacity attribute (or any other attribute). To get the full hover effect we also need to change the opacity back to normal when the mouse leaves the <rect> element by setting the onmouseout function.

<rect id="rect1" x="160" y="10"
width="60" height="60"  fill="blue"
onmouseover="evt.target.setAttribute('opacity', '0.5');"
onmouseout="evt.target.setAttribute('opacity','1)');"/>

This method requires more code, especially if you want to add effects to multiple elements, but gives us a bit more flexibility. For example, if we could chose not to return the opacity to 1 when we move the mouse out of the box, or we could trigger effects with onmouseup or onmousedown events. We also have more freedom in which attributes we change. For example, if we write:

<rect id="rect1" x="160" y="10"
width="60" height="60"  fill="blue"
onmousedown="evt.target.setAttribute('y', '5');"
  onmouseup="evt.target.setAttribute('y', '10');"/>

Then the box will 'jump' when we click on it. Finally, we are also not limited to just effecting the element we've moused over. If we change evt.target to evt.target.parentNode.getElementById('rect2'), we select the element with id='rect2', i.e the green rectangle. This approach however, is a little indirect, and I would suggest using ECMAScript instead.

Set attributeName

We can also add a set element to a <rect> element. This allows us to set an attribute in response to an event, even if that event does not involve the element we are changing. Here I used the rect2.mouseover event to trigger an effect in rect1.

Note that this effect does not work in Firefox Firefox 6 and earlier (I think), which is perhaps the biggest drawback of this method.

  <rect id="rect1" x="160" y="10"
   width="60" height="60" fill="blue">
    <set attributeName="fill-opacity" to="0.5"
     begin="rect2.mouseover" end="rect2.mouseout"/>
  </rect>

The set element is pretty versatile and can be used for various animation effects. For example, with begin="4s", the effect will begin 4 seconds after loading.

ECMAScript

The final method I'll describe is the most involved, but by far the most flexible (for example, we can create a tooltip). It involves using ECMAScript (like JavaScript) to write our own functions. The functions are created within a <script> element. Below is one function to make an element semi-transparent and another to make an element opaque. 

  <script type="text/ecmascript">
    <![CDATA[
      function MakeTransparent(evt) {
        evt.target.setAttributeNS(null,"opacity","0.5");
      }

      function MakeOpaque(evt) {
        evt.target.setAttributeNS(null,"opacity","1");
      }
    ]]>
  </script>

Now we can set the onmouseover and onmouseout functions to equal these custom functions.

  <rect id="rect1" x="160" y="10"
  width="60" height="60" fill="blue"
  onmouseover="MakeTransparent(evt)"
  onmouseout="MakeOpaque(evt)"/>

  <rect id="rect2" x="230" y="10"
  width="60" height="60" fill="green"
  onmouseover="MakeTransparent(evt)"
  onmouseout="MakeOpaque(evt)"/>

Clearly, this method requires a lot more writing for the same effect, but since we can write our own functions, it has the potential to generate much more complex effects. I've written a more detailed description of what can be done with ECMAScript here.

JavaScript

Instead of using ECMAScript the SVG itself, it is also possible to use JavaScript in the HTML that contains the SVG, which I explain here. There are several JavaScript libraries that make this even easier. For example, AmpleSDK or Polymaps, which is specific for SVG maps.

Inkscape images

Since a couple of people have asked, you can use these effect with Inkscape SVGs. Just make sure you target the right attributes (such as 'transform' if you want to move or scale a shape). See the attached star.svg for an example.

AttachmentSize
star.svg2.36 KB

Comments

Awesome! I wish all tutorials were are clear as this one. Thanks for taking the time to write it. 

Thanks, I'm glad you liked it.

Hi, thanks for your page. I'm using inkscape to create an svg file and trying to understand some of these interactive functions. I am viewing my files in opera portable I have used : onmouseover="evt.target.setAttribute('opacity', '0.5');" and the associated mousout function and it works a treat. I then tried to change different attributes and couldn't get any others to work. Are there any particular syntax rules that I need to. If I want to change say the stroke width what should I write. I tried : onmouseover="evt.target.setAttribute('stroke-width', '5');" Thank you so much if you can give me any pointers ! Ed

Hi Ed,

I had a quick test using Opera Portable and the onmouseover events seemed to work. The only thing I can think of is that the default stroke is for there to be no stroke, so if you're going to altered the stroke width, you need to define a colour.

For example, see if this works:

  <rect id="rect1" x="160" y="10" width="60" height="60" fill="blue" stroke="black"
   onmouseover="evt.target.setAttribute('stroke-width', '5');"
    onmouseout="evt.target.setAttribute('stroke-width', '1');"/>

Hope that works,

Peter

Hi Peter,

I tried that and on your file and it works just great. I will keep playing around with my inskscape model and see if I can get the same logic to work. Many thanks,

Ed

I guess something is overriding the onmouseover effect. If you are using CSS to style the stroke then that will take precedence. I'm not really sure how to get around that other than by not using CSS (which is a bit of shame).

Hi and thanks for the great Tutorials... But I've got still one Question.

I haved used Inkscape to draw a star in SVG, but can't get the onmouseover effect working.  The Code that won't work look like this:

<path
   sodipodi:type="star"
   style="fill:#aaaaaa;fill-opacity:0.9...
   id="element123"
   sodipodi:sides="6"
   sodipodi:cx="241.42857"
   sodipodi:cy="203.79076"...
   onmouseover="evt.target.setAttribute('sodipodi:cx', '246');"
   onmouseout="evt.target.setAttribute('sodipodi:cx', '241.42857');"
   inkscape:label="#bg-element123" />

perhaps somone know the correct value to move elements with a path-attribute?

thx Will

thanks for nothing.....

Hi 

please show us how to do this to incscape svg s
Thanks! 

Hi Will and Fönster, sorry I didn't see your comments earlier. The code works the same when using Inkscape SVGs, you just need to make sure you're changing the right attributes.

For example, changing sodipodi:cx, has no effect because it's only interpreted by Inkscape and not most other SVG viewers such as a brower. You can verify this by manually changing the value in your SVG; you won't see any effect when you open the SVG in a browser.

Since you will mainly be dealing with paths, it's easiest to use the transform attribute.

For example, the following will cause a shape to jump up 10 pixels when you mouseover it. I've attached a full example to the bottom of the post (above the comments).  

onmouseover="evt.target.setAttribute('transform', 'translate(0, 0)');" onmouseout="evt.target.setAttribute('transform', 'translate(0, 10)');"

Really great tutorial. Thanks!

How to make it work with <use> elements? I could change only the opacity attribute.  Nothing else changes :-/

And, better still, how to make it work with CSS rules? I don't want to re-declare all those attributes again in the script, I have them already in my CSS styleshit, so the only thing I need is to apply these rules to the element (eg. stroke width or color change etc.).

May be I am late finding this post ( this post 2010 ).

I am open your star attachment in my browser.. its work, cool....
and I see your inserted code in my Inkscape.

Hello. Thanks again for your site.

I am trying to make an svg image of a US map interactive so when you click a state the state flag appears. Could you advise on how to make images appear/disappear with mouse clicks?

Hi, thanks for the useful tips. I don't know why it is not working for me. I am asked to use Java Scripts to write my own function for mouseover and mouse out. Still, it is not working. This is what I have written:

 

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="300">

 

      <script type="text/javascript">

       <![CDATA[

       function FillColor1(evt) {

       evt.target.setAttributeNS(null,"fill","red");

      }

       function FillColor2(evt) {

       evt.target.setAttributeNS(null,"fill","green");

      }

      ]]>

      </script>

      <circle id="face" cx="150" cy="150" r="100" stroke="black" stroke-width="2" fill="yellow"></circle>

      <ellipse id="eyeL" cx="120" cy="100" rx="15" ry="25" style="fill:blue;stroke:black;stroke-width:2" onmouseover="Fillcolor1(evt)" onmouseout="FillColor2(evt)"></ellipse>

      <ellipse id="eyeR" cx="180" cy="100" rx="15" ry="25" style="fill:blue;stroke:black;stroke-width:2" onmouseover="Fillcolor1(evt)" onmouseout="FillColor2(evt)"></ellipse>

      <polygon id="mouth" points="105,180 130,200 170,200 195,180 165,190 135,190" style="fill:blue;stroke:black;stroke-width:2" onmouseover="Fillcolor1(evt)" onmouseout="FillColor2(evt)"></polygon>

      <rect id="nose" x="140" y="145" width="20" height="20" style="fill:blue;stroke-width:2;stroke:black" onmouseover="Fillcolor1(evt)" onmouseout="FillColor2(evt)"></rect>

</svg>

 

thanks,

Mahda

 

Hi Mahda,

There's a couple of things with your code. First, you're calling Fillcolor1(), with a lowercase 'c'. Second, you have styled your shapes using the style attribute which overrides any changes you've made. Change you shapes to be styled like this:

<ellipse id="eyeL" cx="120" cy="100" rx="15" ry="25" fill="blue" stroke="black" stroke-width="2" onmouseover="FillColor1(evt)" onmouseout="FillColor2(evt)"></ellipse>

 

Im making an intereactive map, im implimenting your pop effect code, it works but the svg image moves to the top of the page. 

P.S great tutorials.

Hi,

Sorry, I am late to the page also.  Just a quick question regarding funtionality of the hover effect.  Is it possible to have a hover effect that highlights a common word/concept within the text on a page?

I would really appreciate your help with this.

 

Ta

Cindy

Hi Peter,

Awesome work.

How does this compare with the result generated using CSS3 animation?

Best wishes,

Ashok Koparday 

I find myself coming back to this page frequently.  I have a project that I'm working on that uses an interactive SVG.    I used a google search  for SVG display image on mouseover.   

I used my own class like this 

class="foo-bar"

<style> 
    .foo-bar:hover
    {
      opacity: 0.5;
    }
</style>

 

 

 

Thanks for this tutorial, it saved me a great deal of time.

Patrick,

Nairobi.

I am really grateful for this .... it has helped me a lot.

Post new comment

The content of this field is kept private and will not be shown publicly.