Icons have gotten boring. When I started with vector icons it was a breath of fresh air: the ease of use, scalability, and speed were all superior. But now just about every website uses font awesome, the noun project, or glyphicons. It's repetitive. It's boring. It's hard to change because it works so well.

In this tutorial I want to introduce an easy way to add some flare and excitement to this type of icon: gradient-filled line icons that you can animate using only CSS. It's fast, easy, pretty compatible, and is (at this point) somewhat unique. It's another option to keep things fresh.

TLDR; How it works

The icons are SVG (icon fonts work just as well) and are set on a white backdrop (which is important). The linear-gradient is applied as a background to a layer above the icons. The clipping, and magic, is done with CSS mix-blend-mode . By setting mix-blend-mode: screen to the gradient layer it will essentially dissapear over the white background. Now all we do is add our icons between the gradient layer and the white background and make sure the strokes/fills are black.

Gradient screen on top of black icons = gradient icons. Gradient layer screened on a white background = white. Tada, relatively browser-compatible clipping. The only major limitation is that the background needs to be high contrast: generally anything very dark or very bright works with tweaking. The animation is accomplished by rotating or translating the background using CSS animations.

Background Decisions

To get the effect I was looking for I wanted something that would animate using CSS. The benefit of this is that it isn't deprecated (like SMIL/SVG animations) and it's easier to use and re-apply to multiple icons than JS would be.

Since you can't directly apply a gradient to an SVG path or to text you're left with what is basically clipping. We want to apply a gradient to something else (a CSS background) and then clip that gradient to the icon or text. CSS3 has a built in spec for this with background-clip: text but currently that only works in webkit and would not apply to SVG icons (which is what I prefer to use).

The next obvious choice is to use an svg <linearGradient> and apply that to each SVG path but that has the distinct disadvantage of not being animatable with CSS: it would require either JS or SMIL (which is fading and not super recommended) and you also can't use it with non-svg elements. This method is super compatible though so if you just want a fixed gradient this could be a good choice.

Third and final winner: CSS mix-blend-mode. This method isn't very intuitive: we're talking about blend-mode and not anything clipping-related or gradient related. BUT we can make this behave functionally like a clipping mask by using mix-blend-mode: screen or (for dark backgrounds) mix-blend-mode: multiply . Browser compatibility is also much better than background-clip, though not as good as regular SVG gradients. To see a visual explanation of this in action see the second embedded pen in the TLDR section.

Without further preamble, let's get to the (simple, at this point) tutorial:

Step 1: Pick your background

We need pick a high contrast background for the mix-blend-mode gradient layer to properly clip to our icons. This can either be dark or light: for a dark background you want the gradient to apply via mix-blend-mode: multiply , for a light background the gradient layer should be mix-blend-mode:screen . We'll go with a light background for this:

.icon-background { background-color: white; }

Step 2: Add icons

I'm going to use some free vector line icons from a set designed by Tony Thomas for Medialoot. Any icons should work, the key is that the icon layer needs to be after or above the background layer in the DOM and below the gradient layer.

<div class="icon-background"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 62"><rect x="19" y="6" width="12" height="4"/><rect x="1" y="38" width="48" height="4"/><line x1="25" y1="1" x2="25" y2="6"/><line x1="25" y1="42" x2="25" y2="58"/><line class="cls-1" x1="38" y1="42" x2="44" y2="61"/><line x1="12" y1="42" x2="6" y2="61"/><line x1="8.53" y1="53" x2="41.47" y2="53"/><polygon points="3 38 16.75 25.99 24.59 31.99 36.92 20 47 29.82 47 37.98 3 38"/><circle cx="14" cy="18" r="3"/><polygon points="31 8 31 10 19 10 19 8 3 8 3 38 47 38 47 8 31 8" /> </svg> </div>

Step 3: Create the gradient layer

This layer should immediately follow the icon or icons (depending on how you want it applied) and will have our gradient background set. This is pretty much where everything interesting happens:

<div class="icon-background"> <svg><-- icon is here --></svg> <div class="gradient"></div> </div>

And the CSS:

.gradient{ position: absolute; width:150%; height:150%; top:-25%; left:-25%; mix-blend-mode: screen; pointer-events:none; }

You might have noticed that I'm absolutely positioning the gradient background over the icon. There are a bunch of ways to do this but I think that is probably the easiest way (if you think of a better one let me know). I've also added pointer-events:none to make sure that any pointer events translate through the gradient clip to the icon below.

Step 4: Animate!

This part is pretty easy, just create some animation keyframes and spin your gradient around. You may have to tweak the size of the background-gradient to make sure the corners don't cut off. You may also want to create an icon container with overflow:hidden set to avoid the gradient from hitting any other elements on your page.

.gradient{ animation: spin 1.5s linear infinite alternate; } @-webkit-keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

Final Result

Here's the end result of this technique. I've added a few additional icons and gradients for your viewing pleasure:

Compatibility

According to Can I Use browser support is currently just shy of 75%. In practice, this works well for firefox, chrome, and safari including the mobile versions. It has little to no functionality in IE and MS Edge support is coming. Luckily this technique can be made to degrade very gracefully to just black icons.

Questions, comments, improvements?

This is just a small portion of the cool things that can be done using mix-blend-mode and is only scratching the surface at what we can do to make vector icons more interesting. If you've got other ideas or examples please comment I'd love to hear more.

For reference:

...

Tutorial written by Mason Hipp. Mason is a developer of front-end and server-side javascript with an inclination toward making things pretty and fast. He's a founder of Medialoot and Glyphs Company and is currently trying to write more. This article counts.