Blog Home

Filling External SVGs with CSS Masks

SVGs are common in web design, but styling externally sourced ones via <img> is challenging since the tag doesn’t allow direct style manipulation. CSS masking offers a dynamic, JavaScript-free solution for applying color fills.

Why Can't We Style External SVGs Directly?

When an SVG is embedded via an <img> tag, it is treated as an external resource, like a photograph or raster image. This means:

To overcome this, we can use CSS masking, which treats the SVG as a stencil for dynamic styling.

Why CSS Masks?

CSS masks (and their -webkit-mask counterpart for better browser support) allow you to use an SVG as a mask for an HTML element. This effectively turns the SVG into a stencil through which the background color of the element shows. Masks offer:

Alternative Approach: CSS Filters

You might have come across techniques that use CSS filters to recolor an SVG, such as those generated by tools like CSS Color Filter Generator . While this method works, it has limitations:

Here is an example of what this looks like when trying to turn a black SVG into the color #1e293b:

filter: brightness(0) saturate(100%) invert(13%) sepia(32%) saturate(813%) hue-rotate(177deg) brightness(89%) contrast(90%);

Why this isn't ideal

When we use a color picker to test the resulting color, we find out that the closest color that could be created here is in fact #1f2a3c- not ideal if we have brand guidelines to adhere to.

#1e293b vs #1f2a3c
#1e293b vs #1f2a3c

For scenarios where precise control and clean visuals are critical, CSS masks are a more robust choice.

Step-by-Step Guide

1. Create the HTML Structure

Let's start with a simple <div> element to act as our container:

<div class="svg-mask"></div>

This will serve as the box where the masked SVG will be displayed.

2. Add Basic Styling

Use the mask and -webkit-mask properties to apply an external SVG as a mask:

.svg-mask {
  width: 100px;
  height: 100px;
  background-color: red; /* The color you want to fill the SVG with */

  -webkit-mask: url('https://website.com/path-to-your-svg.svg');
  -webkit-mask-size: contain;

  mask: url('https://website.com/path-to-your-svg.svg');
  mask-size: contain;
}

3. Fix Positioning

This does the job of changing the color, however, you might notice that the masked SVG repeats within the container, and it is also off-center. To fix this, we can use the mask-position and mask-repeat properties:

.svg-mask {
  width: 100px;
  height: 100px;
  background-color: #1e293b;

  -webkit-mask: url('https://website.com/path-to-your-svg.svg');
  -webkit-mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center;

  mask: url('https://website.com/path-to-your-svg.svg');
  mask-size: contain;
  mask-position: center;
  mask-repeat: no-repeat;
}

Final Result

Let's tidy this up - we can use shorthand here, and put a few of these properties within the single mask property. That looks like this:

<div class="svg-mask"></div>

<style>
  .svg-mask {
    width: 100px;
    height: 100px;
    background-color: #1e293b;

    -webkit-mask: url('https://website.com/path-to-your-svg.svg') center / contain no-repeat;
    mask: url('https://website.com/path-to-your-svg.svg') center / contain no-repeat;
  }
</style>

I used this trick to fill the skill SVG's on my homepage, which are being pulled from my CMS:

Icons for each of the skills on my homepage

Browser Compatibility

CSS masking is widely supported, but be sure to include the -webkit- prefix for compatibility with WebKit-based browsers (e.g., Chrome, Safari). Check Can I Use for the latest support details.

Use Cases

This technique is perfect for scenarios where you:

By leveraging CSS masks, you can dynamically style external SVGs efficiently and flexibly. This approach eliminates the need for JavaScript while maintaining clean, accessible code. Happy styling!