##  [Link icons with mask-image and ::before and ::after pseudo elements ](/link-icons-with-mask-image-and-before-and-after-pseudo-elements) 

 On this page

 

Both of the mask-image and pseudo-element CSS features are useful in their own right, but when combined, they make a great way to include icons that can change colour on hover without the need to load a second coloured asset.

I have been using this technique for a while now and am unsure where I first encountered it, but once discovered, I have never looked back.

## Mask-image

A mask-image can be used on any element. At the most basic level, the opaque area of the mask image you place on top of the element is the part of the element that is retained.

Alternatively, looking at it from the other way, transparent areas of the mask image are cut away from the corresponding parts of the element.

In short, only the portions of the element that align with opaque pixels in the mask are kept; transparent pixels in the mask knock out the element underneath.

For icons, this works perfectly as the best way to add icons to a site is using an SVG, and SVG are generally shapes that are 100% alpha (in any colour), and the areas that are not part of the SVG shape are generally transparent.

## The mask image in action

In the example, we are adding some social icons to the page. We want the icons to be the same colour as the text that accompanies the icon, and when we hover, we want the icon to change to the same colour as the text.

[Twitter](#toc-the-mask-image-in-action)


a.twitter-icon {
    background-color: blue;
    color: white;
    text-decoration: none;
    height: 50px;
    padding: 10px;
    width: fit-content;
    display: flex;
    align-items: center;
    gap: 10px;
    transition: background-color 300ms, color 300ms;
  }
  a.twitter-icon::before {
    content: '';
    height: 25px;
    width: 25px;
    background-color: currentColor;
    mask-image: url('data:image/svg+xml,<svg id="icon" width="800px" height="800px" viewBox="0 -2 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>twitter [%23154]<desc>Created with Sketch.<defs><g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Dribbble-Light-Preview" transform="translate(-60.000000, -7521.000000)" fill="%23000000"><g id="icons" transform="translate(56.000000, 160.000000)"><path d="M10.29,7377 C17.837,7377 21.965,7370.84365 21.965,7365.50546 C21.965,7365.33021 21.965,7365.15595 21.953,7364.98267 C22.756,7364.41163 23.449,7363.70276 24,7362.8915 C23.252,7363.21837 22.457,7363.433 21.644,7363.52751 C22.5,7363.02244 23.141,7362.2289 23.448,7361.2926 C22.642,7361.76321 21.761,7362.095 20.842,7362.27321 C19.288,7360.64674 16.689,7360.56798 15.036,7362.09796 C13.971,7363.08447 13.518,7364.55538 13.849,7365.95835 C10.55,7365.79492 7.476,7364.261 5.392,7361.73762 C4.303,7363.58363 4.86,7365.94457 6.663,7367.12996 C6.01,7367.11125 5.371,7366.93797 4.8,7366.62489 L4.8,7366.67608 C4.801,7368.5989 6.178,7370.2549 8.092,7370.63591 C7.488,7370.79836 6.854,7370.82199 6.24,7370.70483 C6.777,7372.35099 8.318,7373.47829 10.073,7373.51078 C8.62,7374.63513 6.825,7375.24554 4.977,7375.24358 C4.651,7375.24259 4.325,7375.22388 4,7375.18549 C5.877,7376.37088 8.06,7377 10.29,7376.99705" id="twitter-[%23154]">');
    mask-size: 25px;
  }
  a.twitter-icon:hover {
    background-color: darkslategray;
    color: lightcyan;
    border-bottom-width: 0;
    &::before {
      /*background-color: currentColor;*/
      background-color: lightskyblue;
    }
  }
}
```css
a {
  background-color: blue;
  height: 50px;
  padding: 10px;
  color: white;
  width: fit-content;
  display: flex;
  align-items: center;
  gap: 10px;
}
 
a::before {
  content: "";
  height: 25px;
  width: 25px;
  background-color: currentColor;
  mask-image: url(twitter.svg);
  mask-size: 25px;
}
 
a:hover {
  background-color: red;
  color: blue;

  &::before {
     /*background-color: currentColor; **Not needed**  */
     /*background-color: lightskyblue;*/
  }  
}
```

We have a few things of interest going on here. So let's have a closer look.

### The Basics of the Code Explained

The pseudo-element `a::before` creates an empty box that is then shaped by the SVG via `mask-image: url(twitter.svg)`. Think of the SVG as a stencil: its opaque (typically one colour) areas is the area that is kept and therefore is shown in the background colour of the box, while transparent areas cut everything away completely; this gives us crisp, hard-edged shapes, and the background colour of the pseudo-element's parent shows through.

By setting `background-color: currentColor` on the pseudo-element, the icon automatically inherits the text colour of its parent `<a>` (via the cascade of colour). This keeps the icon perfectly in sync with the accompanying text colour at all times. On `:hover`, when we change the `<a>`'s colour (and `background-color`), `currentColor` updates instantly, so the icon flips colour seamlessly alongside the text. No extra rules needed for the pseudo-element.

### A couple of other nice bonuses in this setup:

- The SVG file itself can stay simple/single-colour.
- Everything remains lightweight, and you can use a vector-sharp at any size (thanks to mask-size and SVG).
- If you want to style the icon a colour, just override the background colour of the pseudo-element.
- If you want the icon after the text, you can use the `::after` pseudo-element.
- It works great for theming or dark mode too: Just update the link's colour (or a custom property), and the icon follows instantly.   
    See my 2020 article on using `prefers-color-scheme` with CSS custom properties for a solid foundation: [Using Prefers Color Scheme and CSS Custom Properties](/using-prefers-color-scheme-and-css-custom-properties).

If you want to add a transition later, put a `transition: background-color 300ms, color 300ms;` on the `a`, and the mask/icon will smoothly follow too.

## Conclusion

That is it, one rule, one SVG, and you can style icons like a king. No need to complicate things, and thus no need to complicate the conclusion.

However, I think once you understand the mental model of how the mask-image works it becomes a powerful tool; that is, of the mask image used, be that an SVG, a gradient, or PNG, the colour is irrelevant, and only the shape is considered. It works like a stencil and is effectively removed once the shape is cut into the element.

There are other more advance properties of mask such as luminance and composite but for what we discussed here we don't need to worry about them, so we will leave them for another day.

Sign up to my newsletter below for more simple front-end development and design tips. Thanks for reading.

Simon



Tags

[CSS](/css)