There are a lot of different ways to use SVG. Depending on which way, the tactic for recoloring that SVG in different states or conditions — :hover
, :active
, :focus
, class name change, etc. — is different.
Let’s look at the ways.
Inline SVG
Inline SVG is my favorite way to use SVG anyway, in part because of how easy it is to access and style the SVG.
See the Pen
bJXNyy by Chris Coyier (@chriscoyier)
on CodePen.
If you’re used to working with icon fonts, one thing you might enjoy about them is how easy it is to change the color. You’re largely limited to a single color with icon fonts in a way that SVG isn’t, but still, it is appealingly easy to change that single color with color
. Using inline SVG allows you to set the fill
, which cascades to all the elements within the SVG, or you can fill each element separately if needed.
SVG Symbol / Use
There is such thing as an SVG sprite, which is a group of SVGs turned into <symbol>
elements such that any given icon can be referenced easily with a <use>
element.
See the Pen
Use SVG Hovers by Chris Coyier (@chriscoyier)
on CodePen.
You can still set the fill color from outside CSS rather easily this way, but there are caveats.
- The internal SVG elements (like the
<path>
) can have no fill themselves. This allows the fill set from the parent SVG to cascade into the Shadow DOM created by<use>
. As soon as you have something like<path fill="blue" ... />
in the<symbol>
, you’ve lost outside CSS control. - Likewise, the
fill
of individual elements cannot be controlled within the SVG like you could with inline SVG. This means you’re pretty firmly in single-color territory. That covers most use cases anyway, but still, a limitation nonetheless.
SVG background images
SVG can be set as a background image just like PNG, JPG, or whatever other graphics format. At this point, you’ve sort of given up on being able to change the fill
. One possibility, which I’d argue isn’t a particularly good one, is to have two versions of every icon, in the respective colors, and swap between them:
See the Pen
Background SVG Hovers by Chris Coyier (@chriscoyier)
on CodePen.
I don’t blame you if you’d rather not swap sources, so another possibility is to get gnarly with filters.
See the Pen
Background SVG Hovers with Filters by Chris Coyier (@chriscoyier)
on CodePen.
Trying to finagle the right filters to get the color right is tricky stuff. Fortunately, Barrett Sonntag made a tool to calculate the filters for you! Turning black to red ends up a whacky combination like this: invert(27%) sepia(51%) saturate(2878%) hue-rotate(346deg) brightness(104%) contrast(97%);
.
SVG also has object
, which is kinda neat in that it had a built-in fallback back in the day — although browser support is so good these days, I honestly have never used it. But if you’re using it, you would probably have to use this filter
technique to swap color on hover.
See the Pen
Background SVG Object Hovers by Chris Coyier (@chriscoyier)
on CodePen.
Use a mask instead of a background image
This way, the SVG is still in charge of essentially drawing the shape, but the color comes from the background-color
(or image! or gradient!) behind it rather than the SVG itself.
See the Pen
Background SVG Hovers with Mask by Chris Coyier (@chriscoyier)
on CodePen.
SVG background images as data URLs
This doesn’t change that much from above, but it does open up one interesting possibility: Using a variable for the internal fills. Here that is with Sass keeping the URLs as variables:
See the Pen
Background SVG Hovers with Data URL variables by Chris Coyier (@chriscoyier)
on CodePen.
You can also do this with native CSS custom properties!
Overall,
<use>
is my favorite method for implementing SVG icons. You get the benefits of inline SVGs without having to deal with huge blocks of SVG code in your HTML files. Not only that, but the HTML itself becomes much more legible because you have a small, self-descriptive (via the defined ID) element. Plus, you can keep everything in a single separate SVG file that enables proper organization in Illustrator via layers as well as decent readability in a text editor, as well.Thanks for the article. Good refresher!
Thanks for the article. I prefer the
use
method as well. Is there any issue in placing the SVG symbol code in the footer?Also, is it better to inherit the fill colour? https://codepen.io/vj/pen/EzgqeK
thanks man it changed my mind to use from using mask
Isn’t there also the method to refer to an anchor or id in the svg image and display only that?! Can’t really remember, but it was something like
url(image.svg#red-one)
. Can you cover that, too?!I covered that method in part 80 of my Inkscape tutorial for Full Circle Magazine (free download): http://fullcirclemagazine.org/issue-140/
Basically it makes use of the CSS :target selector to only show a specific group in the image. The previous article (in issue 139) also included a method to achieve a similar effect using viewBox and/or named views in the SVG.
Inline and urlencoded SVG are great, especially when you realize how great gzip handles duplicated parts of code, so even few variants of same icon with different colors are not as bad idea as you may think.
I’ve been struggling to find a way to target the individual paths inside of the svg for styling. I want to use an svg as a background pattern for a page and have the path hovered over change color. Is it possible?
The way that I like to do it:
1. SVG: Make the SVG black #000000 where you want to control the color on hover.
2. CSS: fill: currentColor; on the tag.
3. CSS: Change the color attribute in CSS to change the color of the SVG (works with transition!)
Great tutorial but how would I get a path of my svg icon file in my PC? All you do in the tut is using the path for loading each of the icons, but never mentioning about how to get the paths
This PostCSS plugin is pretty neat: https://github.com/TrySound/postcss-inline-svg
It lets you easily change fill/stroke colors in CSS background SVGs
To make the “mask” way of doing it work on iPhone (Firefox, Chrome, not Safari) I had to add the corresponding css rules “-webkit-mask: (url)” and “-webkit-mask-size: cover”.