Question

I have an SVG that uses :hover to change color. It only works when I hover over the solid part of the SVG, not the transparent part. I'm wondering how you could make the SVG interact with the mouse hovering anywhere over the whole SVG. The point of this is to make the SVG a link and the link only clickable on certain portions of the SVG. I don't just want a solution to this particular instance but a solution that works for many instances (If I wanted different parts of the SVG clickable.) The elements in my SVG are directly connected to CSS and grouped with a <g> tag to group the clickable elements.

Edit: the SVG is in an object tag

SVG

<?xml-stylesheet type="text/css" href="svg.css" ?>
<svg xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg3036" version="1.1" inkscape:version="0.48.2 r9819" width="58" height="58">
         <g class="test">
  <path d="M 8.1 32.8 C 7.1 30.1 0.3 -4.6 11.1 4.9 21.9 14.5 15.9 12.8 29 12.8 42.1 12.9 36.1 14.6 46.9 5.1 57.7 -4.5 50.9 30.3 49.9 32.9 48.9 35.6 37.6 54.8 29 54.7 20.4 54.6 9.1 35.4 8.1 32.8 z" id="path3119" inkscape:connector-curvature="0" sodipodi:nodetypes="zzzzzzz" class="wolf"/>
  <path d="M 31.5 23.3 46.6 21" id="path5212" inkscape:connector-curvature="0" sodipodi:nodetypes="cc" class="eyes"/>
  <path d="M 33 23 C 32.3 33.9 45 22 45.2 21" id="path5260" inkscape:connector-curvature="0" sodipodi:nodetypes="cc" class="eyes"/>
  <path sodipodi:nodetypes="cc" inkscape:connector-curvature="0" id="path5262" d="M 26.5 23.3 11.4 21" class="eyes"/>
  <path sodipodi:nodetypes="cc" inkscape:connector-curvature="0" id="path5264" d="M 25 23 C 25.7 33.9 13 22 12.8 21" class="eyes"/>
  </g>
</svg>

CSS

.wolf{
    fill:   none;
    fill-opacity:   0;
    stroke-width:   3.672px;
    stroke-linejoin:    round;
} /*.wolf:hover {
    stroke: #777777;
}*/

.eyes{
    fill:   none;
    fill-opacity: 0;
    stroke-width:   1.26708329px;
}

.test {
    stroke: #5ff6ff;
} .test:hover {
    stroke: #555555;
}     

JSfiddle

Was it helpful?

Solution 4

I posted this question all the way back in 2014. Essentially I was trying to solve two problems, how do I make an svg retain hover effects on a transparent part of an svg(specifically with an svg being used in an object tag so I can use hover effects easily), and how do I make it so that individual aspects of the svg can be used as independent links.

I tried a lot of complicated solutions, and eventually found a very simple solution to the first problem. Simply set a fill(any color will do as long as it's not set to fill: none), and set fill-opacity: 0. This retains the pointer-click events, while keeping the svg transparent. This makes perfect sense in hindsight, but can be confusing if you are using a pre-made svg where the fill may have been set to none(appropriately so.)

Here's an example of what that might look like in practice:

<circle cx="100" cy="75" r="50" style="fill: green; fill-opacity: 0;" />

This will create a circle that will retain any pointer-events(such as hover), despite being completely transparent.

I probably should have posted an answer at the time with this solution, because I assume that's the problem that most people who found this question were probably looking for a solution for. But at the time I felt like the answer was unfinished. I forgot about this question, and my solution to the first problem. But I decided I should revisit this question and give some much needed closure.

Since I asked this question, <a> tags within svg's have received an update, and now it is quite simple to apply links to individual parts of an svg. It works exactly as you would imagine: <a href="" target="_blank">...Your SVG element here</a> which was not exactly the case before(or at least I didn't understand how it worked before). Second problem solved!

Here is a code sandbox that shows the solution working, explained in the context of an svg, embedded with the <object> tag: Working Demo

OTHER TIPS

SVG2 adds a new keyword bounding-box to 'pointer-events' to make this easier. It applies to groups as well as to shapes, in your example it would become:

.test {
  pointer-events: bounding-box;
  stroke: #5ff6ff;
}
.test:hover {
  stroke: #555555;
}

See jsfiddle. Right now that should work in Chrome Canary or Opera Dev builds.

It depends on the shapes, but it's possible to get it working in the currently shipping browsers too. E.g by using pointer-events="all" on the largest shape, and then using CSS selectors creatively to get the stroke applied where you want it. It's a bit tricky since you probably want the stroke to apply to the group although the actually hovered element is the shape inside the group.

Another alternative is to script it using mouseenter and mouseleave events on the <g> element.

The existing 'pointer events' answers to this question helped me get to this solution:

<svg id="example" pointer-events="bounding-box" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 300">

The pointer-events="bounding-box" is best placed within the SVG tag if you have transparent areas you want to be clickable, e.g with an icon or (as above) a logo that links to a website homepage with an embedded link (defined as xlink:href).

You can include pointer-events="visible" in the test <g> and a function call where the function is in the parent HTML (This tested OK in IE/CH/FF) e.g

<svg xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg3036" version="1.1" inkscape:version="0.48.2 r9819" width="58" height="58">
         <g pointer-events="visible" onclick="parent.testHover()" class="test" fill="none" stroke="black" stroke-width="2">
  <path d="M 8.1 32.8 C 7.1 30.1 0.3 -4.6 11.1 4.9 21.9 14.5 15.9 12.8 29 12.8 42.1 12.9 36.1 14.6 46.9 5.1 57.7 -4.5 50.9 30.3 49.9 32.9 48.9 35.6 37.6 54.8 29 54.7 20.4 54.6 9.1 35.4 8.1 32.8 z" id="path3119" inkscape:connector-curvature="0" sodipodi:nodetypes="zzzzzzz" class="wolf"/>
  <path d="M 31.5 23.3 46.6 21" id="path5212" inkscape:connector-curvature="0" sodipodi:nodetypes="cc" class="eyes"/>
  <path d="M 33 23 C 32.3 33.9 45 22 45.2 21" id="path5260" inkscape:connector-curvature="0" sodipodi:nodetypes="cc" class="eyes"/>
  <path sodipodi:nodetypes="cc" inkscape:connector-curvature="0" id="path5262" d="M 26.5 23.3 11.4 21" class="eyes"/>
  <path sodipodi:nodetypes="cc" inkscape:connector-curvature="0" id="path5264" d="M 25 23 C 25.7 33.9 13 22 12.8 21" class="eyes"/>
  </g>
</svg>

EDIT - Added.

I've tested using your svg as the src for an <img> rather than an <object> and placed it in a link. That works, is clickable in all browsers. There is no need to add the pointer-events or functiont call. Therefore you could use img rather than object.

If you want a valid html document in the end. Surround the svg element with an anchor tag if you are planning in turning it into a link.

Also do not forget to turn the link into a block or inline-block element. (This depending on your needs)

There is a hack you can do by using a filter. Filter effects can change fills to transparent without changing their clickability. Below, you add a semi-transparent fill to your graphic, but then use a filter to remove it.

.wolf{
    fill:   blue;
     fill-opacity:  0.09;
    stroke-width:   3.672px;
    stroke-linejoin:    round;
} /*.wolf:hover {
    stroke: #777777;
}*/

.eyes{
    fill:   none;
    fill-opacity: 0;
    stroke-width:   1.26708329px;
}

    <defs>
        <filter id="greenscreen">
        <feComponentTransfer>
            <feFuncA type="table" tableValues="0 0 .2 .3 .4 .5 .6 .7 .8 .9 1"/>
        </feComponentTransfer>
    </filter>
    </defs>
  <g class="test" filter="url(#greenscreen)">

etc.

Edit: svg:hover .test { stroke: #555555}

Ignore previous answer (below) it was addressing a different issue.

Create an empty transparent object - i.e. <rect> that's the size and shape of the <svg> and place it just before the </a></svg> (don't wrap!).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top