How to make transparent part of SVG clickable?
Asked Answered
F

7

24

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

Furniture answered 15/3, 2014 at 1:11 Comment(8)
put the :hover on the svg element? (unless I'm missing something)Asylum
Sorry I forget to add it's in an object tagFurniture
Live example, jsfiddle or something?Hourigan
Set a height and width.Tisbe
The object tag has a height and width. Why would this matter?Furniture
Surround it with a wrapper div and put the hover on that?Toulon
This would work but it will make the whole thing a link, not specified to any certain area.Furniture
The jsfiddle does not existPino
F
2

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

Furniture answered 14/11, 2022 at 6:49 Comment(0)
H
24

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.

Hamish answered 17/3, 2014 at 9:44 Comment(0)
N
8

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).

Newmann answered 17/12, 2018 at 10:58 Comment(1)
How well supported is this? Seems not very :(Rodrique
T
3

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.

Thibodeaux answered 15/3, 2014 at 14:7 Comment(1)
This does make the inside clickable but does it work for any area I would want clickable? This can also be achieved by adding a transparent fill to the "wolf" element. I need this to be a link though, how would that be accomplished, wrapping it in an <a> tag doesn't work.Furniture
F
2

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

Furniture answered 14/11, 2022 at 6:49 Comment(0)
I
0

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)

Invalidism answered 15/3, 2014 at 3:20 Comment(3)
My SVG is already linked inside an object tag. I don't want to change this or I will have to use inline CSS for the SVG. Right now the SVG is connected to the CSS through an external style sheet.Furniture
Hm then I invite you to turning your svg's into a font. This seems to be way more effective to what you want to have made. Check fortawesome.github.io/Font-Awesome for reference and check fontastic.me for creating your own. Creating your own svg library and have a modular type of way of using it over and over again in your site.Invalidism
That is a pretty good solution but I want to know how to do this regardless.Furniture
A
0

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.
Asylum answered 16/3, 2014 at 18:32 Comment(1)
why would it matter if you had a transparent fill left?Furniture
G
0

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!).

Georgianngeorgianna answered 21/8, 2016 at 22:1 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.