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.
When an SVG is embedded via an <img>
tag, it is treated as an external resource, like a photograph or raster image. This means:
<img>
tag itself (e.g., dimensions, borders).To overcome this, we can use CSS masking, which treats the SVG as a stencil for dynamic styling.
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:
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%);
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.
For scenarios where precise control and clean visuals are critical, CSS masks are a more robust choice.
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.
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;
}
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;
}
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:
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.
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!