A reader writes in:
Is there anything on your site that shows me how to make an SVG clickable using CSS? As in, I have an SVG and I click on part of it and it should reveal an outline on that part of the element? I have a telephone interview Tuesday for a job as a remote SVG Illustrator and I don’t want to look like a turkey.
Say I have an <svg>
of The United States and it’s like this:
<svg class="us" viewBox="0 0 500 400">
<path d="..." class="wisconsin" />
<polygon points="..." class="colorado" />
<g class="michigan">
<path d="..." class="michigan--up">
<path d="..." class="michigan--main">
</g>
<!-- etc -->
</svg>
Each state then is kind of a direct descendant of the <svg>
, the selector would be svg.us > *
.
Typically, when I think “clickable”, I think JavaScript. Here’s how we could watch for clicks on each state. We’ll also apply a class to the state clicked:
var allStates = $("svg.us > *");
allStates.on("click", function() {
allStates.removeClass("on");
$(this).addClass("on");
});
That class will do the styling for us. You mentioned an outline, so let’s do that and a fill color as well:
.on {
fill: pink;
stroke: red;
stroke-width: 2;
}
Tada!
See the Pen Click State to Activate by Chris Coyier (@chriscoyier) on CodePen.
But you DID say “clickable using CSS” specifically. That’s a little trickier. Usually we have :focus
in CSS, but I don’t think there is any tried-and-true way to make an SVG element itself focusable. There was talk (long ago) of a focusable
attribute, but I think that’s out. The HTML-way is tabindex, which I believe works in some browsers, but we can’t count on it. I think the best way is using anchors in SVG (yep, we can use them in SVG too!) which are focusable in all browsers. Then apply the :focus
style to the anchor which cascades into the shapes.
Amelia Bellamy-Royds did just this in a StackOverflow thread. Here’s my slightly simplified version:
<svg viewBox="0 0 95 50">
<a xlink:href="#0">
<circle cx="20" cy="25" r="5" data-Name="shape 1" data-tabindex="0" />
</a>
<a xlink:href="#0">
<circle cx="40" cy="25" r="5" data-Name="shape 2" data-tabindex="0" />
</a>
<a xlink:href="#0">
<circle cx="60" cy="25" r="5" data-Name="shape 3" data-tabindex="0" />
</a>
<a xlink:href="#0">
<circle cx="80" cy="25" r="5" data-Name="shape 4" data-tabindex="0" />
</a>
</svg>
a:focus {
fill: pink;
stroke: red;
stroke-width: 1;
}
That should do it:
See the Pen SVG with Focusable Elements by Chris Coyier (@chriscoyier) on CodePen.
There’s
:active
, which works on all elements, but it stops working as soon as you stop holding the button/finger down…Thanks
Wouldn’t it be more efficient to add a single listener to the full map and find the target in the event handler?
It seems a lot easier as @David mentioned.
I went ahead and made a full map version using CSS. Seems a more pertinent example than the circles. If it could be further simplified, I’d like to know.
http://codepen.io/eti313/pen/yeOEJe
The bummer about
:focus
is that it doesn’t work for these kinds of cases with iOS (and maybe other mobile) which makes it pretty unusable for most use-cases.You can still use :hover emulation in a mobile context; in mobile IE, this requires the hovered node to have the attribute aria-haspopup=”true” to work.
Why href=”#0″ for each?
maybe just a anchor for focusable.
You could use hidden radio buttons for each item and use :checked selector to style.
Yeah, that will work in combination with som pointer-events. I did a demo here:
http://codepen.io/sandstedt/pen/NxNeLe (doesn’t work 100%, but almost :P )
It’s not working in Safari 9.0.2… :(
Totally doesn’t work on the iPad I’m viewing this on.
I’d stick to the jquery method .
If anyone is looking for a pure JavaScript version of this using the map as the sole click event delegator:
See the Pen Click State to Activate by Andy Hoffman (@antibland) on CodePen.
thenks…