SVG Icons with CSS Masks
Have you ever inlined SVG icons inside a CSS stylesheet?
It can improve performance by reducing HTTP requests if done selectively.
I do this all the time using a custom property and background-image
to make reusable icons. One downside is the inability to change or transition colours easily. I’ve recently discovered a new technique that solves this issue using the mask
property.
Masking Icons
Go ahead and jump straight to my CodePen demo and hover, or focus, over both buttons. See the difference in icon colour change. That will demonstrate what I’m talking about below.
For my examples I’m using this Bootstrap icon:
In SVG code that is:
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path d="M4 8a.5.5 0 0 1 .5-.5h5.793L8.146 5.354a.5.5 0 1 1 .708-.708l3 3a.5.5 0 0 1 0 .708l-3 3a.5.5 0 0 1-.708-.708L10.293 8.5H4.5A.5.5 0 0 1 4 8"/>
</svg>
I’ve stripped out any colour and presentation attributes. There is only a single <path>
element which will default to a black fill.
This can be inlined as a CSS custom property using a Data URL.
:root {
--arrow: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M4 8a.5.5 0 0 1 .5-.5h5.793L8.146 5.354a.5.5 0 1 1 .708-.708l3 3a.5.5 0 0 1 0 .708l-3 3a.5.5 0 0 1-.708-.708L10.293 8.5H4.5A.5.5 0 0 1 4 8"/></svg>');
}
Depending on your SVG you may need some URI character encoding (e.g. #
to %23
). I’m not sure if the ;utf8
suffix is necessary in modern browsers.
In the past I would reuse this icon in pseudo elements.
button::after {
background: var(--arrow) center center / 100% auto no-repeat;
content: "";
display: block;
height: 1rem;
width: 1rem;
}
You get the idea; create an empty square and set the icon as a background image. The icon colour is the colour of the original SVG.
My new technique is a small change:
button::after {
background: currentColor;
mask: var(--arrow) center center / 100% auto no-repeat;
/** other props... */
}
The mask
property is the exact same value and syntax as background
was previously. Now background
is using the parent button
colour.
Here’s the CodePen demo again.
Use Cases
Neat, right? This is technique perfect for:
- Button icons
- List bullet points
- Custom checkbox icons
Especically when the icon changes colour depending on interactive state, or light and dark theming, for example. This only works for single colour icons. If you need multi-colour you’re best inlining the SVG in the HTML rather than CSS.
Browser support for mask
is coming along nicely.
Exactly 12 years ago this month I wrote “Resolution Independence With SVG” for Smashing Magazine. Back then Internet Explorer 9, which introduced SVG support, was still taking market share from IE8. Kinda wild I’m still figuring out the best way to do icons!