How to change an SVG's colour with CSS

CSS can recolour an SVG that is inline in the page with fill and stroke. For an SVG in an img tag or a background it cannot: use a mask or edit the file.

Published

To change the colour of an SVG with CSS, the SVG must be inline in the HTML, and the properties to set are fill and stroke, not color. An SVG loaded through an <img> tag or a CSS background is a separate document that the page’s CSS cannot reach: for those, use a CSS mask, or change the colours in the file itself.

Inline SVG: fill and stroke

When the <svg> markup sits in the page, its shapes are ordinary elements and CSS can select them.

<svg class="icon" viewBox="0 0 24 24" width="24" height="24">
  <path d="M12 2 2 22h20z"/>
</svg>
.icon { fill: crimson; }

fill colours the inside of a shape and stroke colours its outline. For an icon drawn with lines, set the stroke and switch the fill off:

.icon-outline { fill: none; stroke: crimson; stroke-width: 2; }

SVG fill and stroke covers both properties in full.

Why the colour does not change

Most SVG files come out of an editor with colours already written on the shapes. Whether your CSS beats them depends on how they were written.

How the file sets the colourDoes a CSS rule override it?
Nothing setYes. The shape inherits fill from its parent
An attribute: <path fill="#000">Yes, but only by a rule that selects the path itself, such as .icon path { fill: red }
An inline style: <path style="fill:#000">Only with !important
A <style> block inside the SVGIt is ordinary CSS: your rule needs higher specificity, or equal specificity and a later place in the page

The second row catches most people. An attribute such as fill="#000" is the weakest kind of style and loses to any CSS rule, but the rule has to match that element. .icon { fill: red } sets the colour on the <svg>, and the path keeps its own value because a value set on an element always beats an inherited one.

The cleanest fix is in the file: delete the fill attributes from the shapes, or change them to currentColor. The SVG viewer lets you edit the code and save the result.

currentColor: follow the text colour

currentColor is a keyword meaning “the value of the color property here”. Use it as the fill and the icon takes the colour of the text around it.

<a class="button" href="/cart/">
  <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor">
    <path d="M12 2 2 22h20z"/>
  </svg>
  Basket
</a>
.button { color: #333; }
.button:hover { color: #0a58ca; }

The icon and the word change colour together, with no CSS aimed at the SVG at all. Many icon sets work this way.

Change the colour on hover

For an inline SVG, hover is one more rule:

.icon { fill: #555; transition: fill 0.2s; }
.icon:hover { fill: crimson; }

In practice, put the hover on the link or button that contains the icon. An icon is a small target, and the whole control should react:

.button:hover .icon { fill: crimson; }

With currentColor, changing color on the parent is enough, as above.

Several colours in one SVG

Give the parts class names and style each, or use custom properties so that one rule on a parent sets a whole palette:

.logo .mark { fill: var(--brand, #e4572e); }
.logo .word { fill: var(--ink, #222); }
.dark .logo { --ink: #fff; }

Custom properties are inherited, so they pass into every shape inside.

SVG in an img tag or a CSS background

<img src="icon.svg" alt="">

CSS on the page cannot restyle this. The browser treats the file as a finished picture: no selector reaches inside it, and fill on the <img> does nothing. There are four ways round it.

1. Inline the SVG. Paste the markup into the page in place of the <img>. SVG in HTML compares the ways of placing one.

2. Use it as a mask. For an icon of one colour, let the SVG supply the shape and CSS supply the colour:

.icon {
  display: inline-block;
  width: 24px;
  height: 24px;
  background-color: currentColor;
  -webkit-mask: url(icon.svg) no-repeat center / contain;
  mask: url(icon.svg) no-repeat center / contain;
}

The element is painted with background-color wherever the SVG is opaque. Any colour, hover included, is then a change of color or background-color. The prefixed line is for older browsers.

3. Use a filter. filter: brightness(0) turns any icon black, and filter: brightness(0) invert(1) turns it white. Other colours need a chain of filters that only approximates the target, so this is best kept for black and white.

4. Change the file. Open the SVG, change the fill values, and save a second copy in the new colour. For a CSS background you can also write the SVG into the stylesheet as a data URI with the colour you want: SVG to data URI makes one, with # escaped as %23 so the colour survives.

SVG sprites and use

Icons drawn with <use href="icons.svg#cart"> sit in between. Selectors cannot reach the shapes inside the referenced symbol, but inherited properties do pass in. If the shapes in the sprite have no fill of their own, or use currentColor, then fill or color set on the <svg> that holds the <use> colours them.

To change the colours stored in the file itself, without writing any CSS, the colour changer lists every colour an SVG uses and swaps each for the one you pick.

Common problems

What you seeCauseFix
fill in CSS does nothingThe SVG is in an <img> or a backgroundInline it, or use a mask
color: red does nothingShapes are painted by fill, not colorSet fill="currentColor" on the SVG
Only some parts changeSome shapes carry their own fill attribute or inline styleSelect those shapes directly, or remove the attributes
The icon turns into a solid blobIt is drawn with strokes and has now been filledUse fill: none and set stroke
Hover only works when the pointer is exactly on a lineThe hover rule is on thin shapesPut the hover on the link or button around the icon
The colour changes but a gradient does notGradient colours live in <stop> elementsStyle stop-color on the stops

Questions

Can CSS change the colour of an SVG background image? Not directly. Use the mask method on an element of its own, or a data URI with the colour written in.

Does this work for a PNG? The mask and filter methods do, since both only use the picture’s shape. fill and stroke are for SVG shapes only.

Is there a way to change colours for cutting, not for a web page? CSS only affects how a browser shows the SVG. For a file going to a cutting machine, change the fill values in the file with a vector editor or the SVG viewer.