How to change SVG color with CSS

Table of contents

I saw a lot of cases in my career when CSS beginners exported same SVG icon files twice just to put it in the layout with different color.

Let's look on example:

Carousel

Here we have a typical carousel component with arrows navigation. In rest state the arrow is grey, on hover - it changes its color to another. CSS beginners may want to just export 2 different SVGs: white one and blue one - and put it in CSS as 2 different SVG files. But let's think about this idea more deeply.

Why duplicating SVGs is bad idea

This approach opens several issues because it is not flexible:

What solution is better

Fortunately there is a way to colorize SVGs while having only one initial file.

Let me introduce you mask-image CSS rule. By utilizing this rule we can change our approach of showing SVG icon by moving from background: url(icon.svg) rule to mask-image: url(icon.svg) plus some additional mask rules.

This mask-image rule works very similar to Photoshop masks - it takes your HTML element and "cuts out" a figure inside it in the form of your SVG.

After that we can set any background color to our element and this "cut out" figure will be colorized to it.

Here is mask-image rule usage example:

.arrow {
  --arrow-svg: url('https://raw.githubusercontent.com/rodion-arr/blog/main/content/images/2023/08/colorize-svg/arrow.svg');
  background: none;
  outline: none;
  border: none;
  width: 40px;
  height: 40px;
  cursor: pointer;

  /* initial arrow SVG color */
  background: black;

  /* mask-image rules */
  mask-image: var(--arrow-svg);
  mask-repeat: no-repeat;
  mask-size: contain;
  mask-position: center;
  -webkit-mask-image: var(--arrow-svg);
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-size: contain;
  -webkit-mask-position: center;
}

/* changing background of element will change SVG color*/
.arrow:hover {
  background: red;
}

We can change background color for .arrow to any without the need of adding new SVG files.

As you can see - there are 2 sets of mask rules: simple and webkit-prefixed. More info on this you can find here - Vendor Prefix

Working CSS example

SCSS mixin for SVG mask

As colorizing SVGs is so common task - those who use SCSS in projects may want to utilize an mixin for reusing set of mask rules in one place and pass a SVG url as parameter.

This mixin assumes that you have configured autoprefixer in your project.

Mask mixin:

// _svg.scss fils
@mixin mask($imgUrl) {
  mask-image: $imgUrl;
  mask-repeat: no-repeat;
  mask-size: contain;
  mask-position: center;
}

Usage:

@use "./svg";

.arrow {
  // other rules here

  @include svg.mask(url('https://raw.githubusercontent.com/rodion-arr/blog/main/content/images/2023/08/colorize-svg/arrow.svg'));
}