Go to homepage

← All articles Last edited:

How to change SVG color with CSS

In this article, we will see how to control the color of inline SVGs using CSS. We'll discuss the benefits of using CSS over inline attributes, focusing on how CSS improves maintainability as your icon system grows in complexity.

When working with SVG icons, colors are typically managed through two inline attributes: fill and stroke. The fill attribute is used to color the interior of an element, while the stroke is used to color the element's border.

Below is an example of SVG icons from the Nucleo library: the first row features icons with only fill color, while the second row shows icons with only a stroke color.

SVG fill and stroke
SVG icons with fill (first row) and stroke (second row) - from the Nucleo library

Here's an example of SVG code, where various elements are defined with either a stroke or fill attribute, both set to red.

<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
  <circle stroke="red" stroke-width="1" fill="none" cx="9" cy="9" r="7.25"></circle>
  <path stroke="red" stroke-width="1" fill="none" d="M9.75,13.875..."></path>
  <path fill="red" stroke="none" d="M5.709,..."></path>
  <path fill="red" d="M12.291,..."></path>
</svg>

When using SVGs as inline elements — e.g., directly embedding the SVG code into the HTML document — CSS can be used to adjust the icon's color. However, it is important to consider specificity.

Working with SVG icons?Take your designs to the next level with the Nucleo icons →

For example, if a path element specifies its fill color as an inline attribute, it cannot be overridden by CSS unless targeted directly. Consider the following SVG icon:

<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
  <path fill="red" d="..."></path>
</svg>

Of the two CSS rules below, only the second will work:

/* this will not work */
svg {
  fill: blue; 
}

/* this will work */
svg path {
  fill: blue; 
}

As the complexity of the SVG code increases, controlling and maintaining specificity becomes challenging.

An alternative and better approach involves using the currentcolor CSS keyword:

<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
  <!-- use currentcolor for fill and stroke attributes -->
  <path fill="currentcolor" d="..."></path>
  <circle stroke="currentcolor" stroke-width="1" fill="none" cx="9" cy="9" r="7.25"></circle>
</svg>

The currentcolor keyword represents the value of an element's color property. By assigning currentcolor as the value for fill and stroke, these attributes automatically inherit the color specified by the element's color property. This means you only need to control the SVG's color to adjust both fill and stroke dynamically, regardless of specificity:

svg {
  color: red; 
}

This makes it easy to control your icons and create color variations:

.icon {
  /* applies to all SVGs with a class of icon */
  color: blue; 
}

.icon--accent {
  /* applies to all SVGs with a class of icon--accent */
  color: red; 
}

@media (prefers-color-scheme: dark) {
  /* applies to all SVGs with a class of icon if user requested dark color theme */
  .icon {
    color: white; 
  }
}

If you are using an icon organizer like Nucleo to store all your icons, you can automatically export your SVGs using currentcolor for fill and stroke (click the icons to select them, right click -> Export):

Nucleo export window
Export SVGs using currentcolor for stroke and fill attributes

You may have noticed that, if an element does not have a fill color, we explicitly add a fill="none" to it, while if an element does not have the stroke color, we omit the stroke inline attribute:

<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
  <!-- this path element does not have a stroke - stroke attribute is not set inline -->
  <path fill="currentcolor" d="..."></path>
  <!-- this circle element does not have a fill - fill attribute is set to none  -->
  <circle stroke="currentcolor" stroke-width="1" fill="none" cx="9" cy="9" r="7.25"></circle>
</svg>

That's because fill and stroke have two different default values. By default, fill is equal to black, so you need to set it to none to remove it from an element. On the other hand, the stroke default value is none, so you won't need to explicitly add it.

If you want to create icons with more than one color, you can use CSS custom properties to define inline fill/stroke values.

In the example below, the fill of the <path> element is set equal to var(--color-primary), while the stroke of the <circle> element is set equal to var(--color-secondary):

<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
  <path fill="var(--color-primary)" d="..."></path>
  <circle stroke="var(--color-secondary)" stroke-width="1" fill="none" cx="9" cy="9" r="7.25"></circle>
</svg>

By default, both variables can be equal to currentcolor (monotone icons):

.icon {
  /* control both variables using the CSS color property */
  --color-primary: currentcolor;
  --color-secondary: currentcolor;
  color: red; 
}

Color variations can then be created by modifying the values of these CSS variables::

.icon--twotone {
  --color-primary: black;
  --color-secondary: yellow;
}

The end! Check our documentation tutorials page for more articles on working with icons.

Cookie Compliance

We use cookies to give you the best possible website experience. Learn more.