The Many Ways to Change an SVG Fill on Hover (and When to Use Them) | CSS-Tricks (2023)

Table of Contents
CSS Filters SVG Filters FAQs

SVG is a great format for icons. Vector formats look crisp and razor sharp, no matter the size or device — and we get tons of design control when using them inline.

SVG also gives us another powerful feature: the ability to manipulate their properties with CSS. As a result, we can make quick and simple interactions where it used to take crafty CSS tricks or swapping out entire image files.

Those interactions include changing color on hover states. It sounds like such a straightforward thing here in 2019, but there are actually a few totally valid ways to go about it — which only demonstrates the awesome powers of SVG more.

First off, let’s begin with a little abbreviated SVG markup:

<svg class="icon"> <path .../></svg>

Target the .icon class in CSS and set the SVG fill property on the hover state to swap colors.

.icon:hover { fill: #DA4567;}

This is by far the easiest way to apply a colored hover state to an SVG. Three lines of code!

SVGs can also be referenced using an <img> tag or as a background image. This allows the images to be cached and we can avoid bloating your HTML with chunks of SVG code. But the downside is a big one: we no longer have the ability to manipulate those properties using CSS. Whenever I come across non-inline icons, my first port of call is to inline them, but sometimes that’s not an option.

I was recently working on a project where the social icons were a component in a pattern library that everyone was happy with. In this case, the icons were being referenced from an <img> element. I was tasked with applying colored :focus and :hover styles, without adjusting the markup.

So, how do you go about adding a colored hover effect to an icon if it’s not an inline SVG?

CSS Filters

CSS filters allow us to apply a whole bunch of cool, Photoshop-esque effects right in the browser. Filters are applied to the element after the browser renders layout and initial paint, which means they fall back gracefully. They apply to the whole element, including children. Think of a filter as a lens laid over the top of the element it’s applied to.

These are the CSS filters available to us:

  • brightness(<number-percentage>);
  • contrast(<number-percentage>);
  • grayscale(<number-percentage>);
  • invert(<number-percentage>);
  • opacity(<number-percentage>);
  • saturate(<number-percentage>);
  • sepia(<number-percentage>);
  • hue-rotate(<angle>);
  • blur(<length>);
  • drop-shadow(<length><color>);

All filters take a value which can be changed to adjust the effect. In most cases, this value can be expressed in either a decimal or percent units (e.g. brightness(0.5) or brightness(50%)).

Straight out of the box, there’s no CSS filter that allows us to add our own specific color.
We have hue-rotate(), but that only adjusts an existing color; it doesn’t add a color, which is no good since we’re starting with a monochromatic icon.

The game-changing bit about CSS filters is that we don’t have to use them in isolation. Multiple filters can be applied to an element by space-separating the filter functions like this:

.icon:hover { filter: grayscale(100%) sepia(100%);}

If one of the filter functions doesn’t exist, or has an incorrect value, the whole list is ignored and no filter will be applied to the element.

When applying multiple filter functions to an element, their order is important and will affect the final output. Each filter function will be applied to the result of the previous operation.

The Many Ways to Change an SVG Fill on Hover (and When to Use Them) | CSS-Tricks (1)

So, in order to colorize our icons, we have to find the right combination.

To make use of hue-rotate(), we need to start off with a colored icon. The sepia() filter is the only filter function that allows us to add a color, giving the filtered element a yellow-brown-y tinge, like an old photo.

The output color is dependent on the starting tonal value:

The Many Ways to Change an SVG Fill on Hover (and When to Use Them) | CSS-Tricks (2)

In order to add enough color with sepia(), we first need to use invert() to convert our icon to a medium grey:

.icon:hover { filter: invert(0.5)}
The Many Ways to Change an SVG Fill on Hover (and When to Use Them) | CSS-Tricks (3)

We can then add the yellow/brown tone with sepia():

.icon:hover { filter: invert(0.5) sepia(1);}
The Many Ways to Change an SVG Fill on Hover (and When to Use Them) | CSS-Tricks (4)

…then change the hue with hue-rotate():

.icon:hover { filter: invert(0.5) sepia(1) hue-rotate(200deg); }
The Many Ways to Change an SVG Fill on Hover (and When to Use Them) | CSS-Tricks (5)

Once we have the rough color we want, we can tweak it with saturation() and brightness():

.icon:hover { filter: invert(0.5) sepia(1) hue-rotate(200deg) saturate(4) brightness(1);}
The Many Ways to Change an SVG Fill on Hover (and When to Use Them) | CSS-Tricks (6)

I’ve made a little tool for this to make your life a little easier, as this is a pretty confusing process to guesstimate.

See the Pen CSS filter example by Cassie Evans (@cassie-codes)
on CodePen.

Even with the tool, it’s still a little fiddly, not supported by Internet Explorer, and most importantly, you’re unable to specify a precise color.

Desktop

ChromeFirefoxIEEdgeSafari
18*35No796*

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
1041014.4*6.0-6.1*

So, what do we do if we need a specific hex code?

SVG Filters

If we need more precise control (and better browser support) than CSS filters can offer, then it’s time to turn to SVG.

Filters originally came from SVG. In fact, under the hood, CSS filters are just shortcuts to SVG filters with a particular set of values baked in.

Unlike CSS, the filter isn’t predefined for us, so we have to create it. How do we do this?

This is the syntax to define a filter:

<svg xmlns="<http://www.w3.org/2000/svg>" version="1.1"> <defs> <filter id="id-of-your-filter"> ... ... </filter> ... </defs></svg>

Filters are defined by a <filter> element, which goes inside the <defs> section of an SVG.

SVG filters can be applied to SVG content within the same SVG document. Or, the filter can be referenced and applied to HTML content elsewhere.

To apply an SVG filter to HTML content, we reference it the same way as a CSS filter: by using the url() filter function. The URL points to the ID of the SVG filter.

.icon:hover { filter: url('#id-of-your-filter');}

The SVG filter can be placed inline in the document or the filter function can reference an external SVG. I prefer the latter route as it allows me to keep my SVG filters tidied away in an assets folder.

.icon:hover { filter: url('assets/your-SVG.svg#id-of-your-filter');}

Back to the <filter> element itself.

<filter id="id-of-your-filter"> ... ...</filter>

Right now, this filter is empty and won’t do anything as we haven’t defined a filter primitive. Filter primitives are what create the filter effects. There are a number of filter primitives available to us, including:

  • [<feBlend>]
  • [<feColorMatrix>]
  • [<feComponentTransfer>]
  • [<feComposite>]
  • [<feConvolveMatrix>]
  • [<feDiffuseLighting>]
  • [<feDisplacementMap>]
  • [<feDropShadow>]
  • [<feFlood>]
  • [<feGaussianBlur>]
  • [<feImage>]
  • [<feMerge>]
  • [<feMorphology>]
  • [<feOffset>]
  • [<feSpecularLighting>]
  • [<feTile>]
  • [<feTurbulence>]

Just like with CSS filters, we can use them on their own or include multiple filter primitives in the <filter> tag for more interesting effects. If more than one filter primitive is used, then each operation will build on top of the previous one.

For our purposes we’re just going to use feColorMatrix, but if you want to know more about SVG filters, you can check out the specs on MDN or this (in progress, at the time of this writing) article series that Sara Soueidan has kicked off.

feColourMatrix allows us to change color values on a per-channel basis, much like channel mixing in Photoshop.

This is what the syntax looks like:

<svg xmlns="<http://www.w3.org/2000/svg>" version="1.1"> <defs> <filter id="id-of-your-filter"> <feColorMatrix color-interpolation-filters="sRGB" type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "/> </filter> ... </defs></svg>

The color-interpolation-filters attribute specifies our color space. The default color space for filter effects is linearRGB, whereas in CSS, RGB colors are specified in the sRGB color space. It’s important that we set the value to sRGB in order for our colors to match up.

Let’s have a closer look at the color matrix values.

The Many Ways to Change an SVG Fill on Hover (and When to Use Them) | CSS-Tricks (7)

The first four columns represent the red, green and blue channels of color and the alpha (opacity) value. The rows contain the red, green, blue and alpha values in those channels.

The M column is a multiplier — we don’t need to change any of these values for our purposes here. The values for each color channel are represented as floating point numbers in the range 0 to 1.

We could write these values as a CSS RGBA color declaration like this:

The Many Ways to Change an SVG Fill on Hover (and When to Use Them) | CSS-Tricks (8)

The values for each color channel (red, green and blue) are stored as integers in the range 0 to 255. In computers, this is the range that one 8-bit byte can offer.

By dividing these color channel values by 255, the values can be represented as a floating point number which we can use in the feColorMatrix.

And, by doing this, we can create a color filter for any color with an RGB value!

Like teal, for example:

The Many Ways to Change an SVG Fill on Hover (and When to Use Them) | CSS-Tricks (9)

See the Pen
SVG filter – teal hover
by Cassie Evans (@cassie-codes)
on CodePen.

This SVG filter will only impart color to icons with a white fill, so If we have an icon with a black fill, we can use invert() to convert it to white before applying the SVG filter.

.icon:hover { filter: invert(100%) url('assets/your-SVG.svg#id-of-your-filter');}

If we just have a hex code, the math is a little trickier, although there are plenty of hex-to-RGBA converters out there. To help out, I’ve made a HEX to feColorMatrix converter.

See the Pen
HEX to feColorMatrix converterr
by Cassie Evans (@cassie-codes)
on CodePen.

Have a play around, and happy filtering!

FAQs

Can I change SVG color on hover? ›

Target the . icon class in CSS and set the SVG fill property on the hover state to swap colors. This is by far the easiest way to apply a colored hover state to an SVG.

How do you change SVG fill using CSS? ›

You can't change the color of an image that way. If you load SVG as an image, you can't change how it is displayed using CSS or Javascript in the browser. If you want to change your SVG image, you have to load it using <object> , <iframe> or using <svg> inline.

Can we change SVG image color using CSS? ›

Edit your SVG file, add fill="currentColor" to svg tag and make sure to remove any other fill property from the file. Note that currentColor is a keyword (not a fixed color in use). After that, you can change the color using CSS, by setting the color property of the element or from it's parent.

Which property is used to change the color of an SVG using CSS? ›

The fill property is a presentation attribute used to set the color of a SVG shape.

How do I change dynamic color in SVG? ›

JS
  1. function color() {
  2. document. getElementById("change1"). style. background = document. getElementById('color1'). value;
  3. document. getElementById("change2"). style. background = document. getElementById('color2'). value;
  4. document. getElementById("kiwi"). style. fill = document. getElementById('color2'). value;
  5. };

How can I change image on hover? ›

Answer: Use the CSS background-image property

You can simply use the CSS background-image property in combination with the :hover pseudo-class to replace or change the image on mouseover.

How do I fill an SVG file? ›

The fill is the color inside a shape, and the stroke is the visible outline of an object. You can fill a shape with one color and stroke it with another. If you create an SVG shape but don't set the fill color, the shape will be colored in black.

How do I change the color of an SVG image? ›

How to: Change colors on a SVG using Cricut Design Space - YouTube

How do I edit a SVG file? ›

To edit an SVG image in Office for Android, tap to select the SVG you want to edit and the Graphics tab should appear on the ribbon. Styles - These are a set of predefined styles you can add to quickly change the look of your SVG file.

How do I change the color of an image in CSS? ›

We can change the image color in CSS by combining the opacity() and drop-shadow() functions in the filter property. We can provide the color of the shadow from the drop-shadow function, and we can set the shadow as thin as possible so that the image's color will only change without forming an actual shadow.

How do I add color to black and white SVG? ›

How To Add Color To SVG (Using Contour) - YouTube

Can I use CSS mask image? ›

CSS masking gives you the option of using an image as a mask layer. This means that you can use an image, an SVG, or a gradient as your mask, to create interesting effects without an image editor. When you clip an element using the clip-path property the clipped area becomes invisible.

Which SVG attribute can be used as a CSS property to style borders or lines around an SVG element? ›

The stroke property in CSS is for adding a border to SVG shapes. Remember: This will override a presentation attribute <path stroke="#fff" ... />

How use SVG icons in HTML CSS? ›

SVG images can be written directly into the HTML document using the <svg> </svg> tag. To do this, open the SVG image in VS code or your preferred IDE, copy the code, and paste it inside the <body> element in your HTML document. If you did everything correctly, your webpage should look exactly like the demo below.

What is fill rule in SVG? ›

The fill-rule attribute is a presentation attribute defining the algorithm to use to determine the inside part of a shape. Note: As a presentation attribute, fill-rule can be used as a CSS property. You can use this attribute with the following SVG elements: <altGlyph> <path>

How do I fill color in SVG? ›

You can set the green and red RGB colors like this: stroke="rgb(0,255,0)" or fill="rgb(255,0,0)" . RGBA(Red, Blue, Green, Alpha) Color Codes. RGBA color values are an extension of RGB color values with an alpha channel that determines the opacity of the color.

How change SVG color react? ›

To change the color of an SVG in React:

Don't set the fill and stroke attributes on the SVG. Import the SVG as a component. Set the fill and stroke props on the component, e.g. <MyLogo fill="black" stroke="yellow" /> .

How do I change the color of an SVG in Photoshop? ›

Editing SVG Font Colors in Photoshop and Illustrator - YouTube

How do I add color to black and white SVG? ›

How To Add Color To SVG (Using Contour) - YouTube

What is fill rule in SVG? ›

The fill-rule attribute is a presentation attribute defining the algorithm to use to determine the inside part of a shape. Note: As a presentation attribute, fill-rule can be used as a CSS property. You can use this attribute with the following SVG elements: <altGlyph> <path>

How do I make multiple colors in SVG? ›

How to Recolour SVGs in Cricut Design Space - YouTube

What is the difference between stroke and fill? ›

Using fill sets the color inside the object and stroke sets the color of the line drawn around the object.

Top Articles
Latest Posts
Article information

Author: Aron Pacocha

Last Updated: 29/10/2023

Views: 5974

Rating: 4.8 / 5 (48 voted)

Reviews: 95% of readers found this page helpful

Author information

Name: Aron Pacocha

Birthday: 1999-08-12

Address: 3808 Moen Corner, Gorczanyport, FL 67364-2074

Phone: +393457723392

Job: Retail Consultant

Hobby: Jewelry making, Cooking, Gaming, Reading, Juggling, Cabaret, Origami

Introduction: My name is Aron Pacocha, I am a happy, tasty, innocent, proud, talented, courageous, magnificent person who loves writing and wants to share my knowledge and understanding with you.