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!