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 colour | Does a CSS rule override it? |
|---|---|
| Nothing set | Yes. 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 SVG | It 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 see | Cause | Fix |
|---|---|---|
fill in CSS does nothing | The SVG is in an <img> or a background | Inline it, or use a mask |
color: red does nothing | Shapes are painted by fill, not color | Set fill="currentColor" on the SVG |
| Only some parts change | Some shapes carry their own fill attribute or inline style | Select those shapes directly, or remove the attributes |
| The icon turns into a solid blob | It is drawn with strokes and has now been filled | Use fill: none and set stroke |
| Hover only works when the pointer is exactly on a line | The hover rule is on thin shapes | Put the hover on the link or button around the icon |
| The colour changes but a gradient does not | Gradient colours live in <stop> elements | Style 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.