I'm Dudley Storey, the author of Pro CSS3 Animation. This is my blog, where I talk about web design and development with HTML, CSS and SVG. To receive more information, including news, updates, and tips, you should follow me on Twitter or add me on Google+.

my books

Pro CSS3 Animation book coverPro CSS3 Animation, Apress, 2013

my other blogs

Massive Head CanonMassive Head Canon: Intelligent discussion of movies, books, games, and technology.

my projects

The New DefaultsThe New Defaults — A Sass color keyword system for designers.

CSSslidyCSSslidy — an auto-generated #RWD image slider. 3.8K of JS, no JQuery.

Better Buttons With Blend Modes and Filters

Creating different icon states with blend modes

Developers and designers use a variety of techniques to create site icons that change on hover or use, often by drawing different icon states in sprite sheets. These techniques are labor-intensive, and make later design changes difficult. More advanced techniques, such as transitioning changes in SVG icons via CSS, are an improvement, but still must be written on a per-icon basis.

Ideally, we would create icons just once, in their final state, and use CSS to present them in an “inactive” state, switching to “active” with a single declaration. With CSS blend modes and filters, you can do just that.

Inverting A Link

A good example might be a variation on the link to CodePen that currently appears at the bottom of many articles on this blog:

<a href="//codepen.io/dudleystorey/pen/KAJtc" id="codepen"><img src="codepen-fill-white.svg" alt>Experiment with this code on CodePen</a>

This markup has the obvious disadvantage that every time the link is created, the SVG image must be inserted within it, which also makes it difficult to change. The CSS for the element reflects this complication:

a#codepen {
display: block; clear: both;
text-decoration: none; margin: 2rem 0;
background: rgba(0,0,0,0.2);
padding: .6rem; transition: .6s;
}
a#codepen img {
width: 60px; height: 60px;
vertical-align: middle;
margin-right: 2rem;
}

Both markup and presentation could be cleaned up substantially by placing the SVG image as a CSS background to the element, rather than an actual <img> tag. The HTML would become:

<a href=//codepen.io/dudleystorey/pen/KAJtc id=codepen>Experiment with this code on CodePen</a>

And the CSS:

a#codepen {
  display: block;
  text-decoration: none;
  color: #fff;
  padding: 2rem;
  padding-left: 7rem;
  background: url(codepen-fill-white.svg) #000 no-repeat;
  background-size: 80% 80%;
  background-position: -150% 50%;
}

Let’s say that we wanted to completely reverse the appearance of the link on hover / focus: black elements becoming white and vice-versa. The basics are very easy:

a#codepen:hover, a#codepen:focus {
  background-color: #fff;
  color: #000;
  border: 1px solid #666;
}

But the CodePen logo resolutely remains black on white, meaning that it will look weird in the rollover state for the link. Normally, this would be where icon sprites would be employed, but we can solve the problem adding a single line to the CSS above:

background-blend-mode: difference;

The result: Explore the pen for this project

Filters for Icons

Another example might be the new primary navigation icons I am currently designing for the next version of this site, which you can see at the top of this article. Each icon is a tiny, separate SVG document, loaded as a background image for a series of links:

<nav>
<a href="/search.php" title="Search"></a>
<a href="//twitter.com/dudleystorey" title="Twitter"></a>
<a href="/archive.php" title="Archive"></a>
<a href="/feed.rss" title="RSS feed"></a>
<a href="?reverse" title="Change article order to oldest first"></a>
</nav>

The icons are designed and drawn in their “active” state, using attribute selectors:

nav a[href="/search.php"] { background: url(search.svg); }
nav a[href*="twitter"] { background: url(twitter.svg); }
nav a[href="/archive.php"] { background: url(calendar.svg); }
nav a[href="?reverse"] { background: url(reverse.svg); }
nav a[href="/feed.rss"] { background: url(rss.svg); }

For the default navigation, I want every icon to display in the same neutral gray. I can achieve that by reducing their contrast to 0:

nav a { width: 50px; height: 50px; filter: contrast(0); }

When the user hovers / focuses a link, I change that to full contrast:

nav a:hover { filter: contrast(1); }

There are a few limitations to note about this technique:

  1. Right now, filter: contrast isn’t well-supported cross-browser, although that will change with Firefox 35; creating an equivalent result for earlier versions of Firefox would entail adding an SVG greyscale filter, as I have done here (see the CodePen demo).
  2. Similarly, until Microsoft gets its act in gear with regard to filters, IE 10+ users will see the full-color version of the icons in all states (IE9 and earlier will have the proprietary MS-only filter: grey;)

In this second case background-blend-mode: luminosity; and filter: contrast would create pretty much the same results, although there are a few differences to consider between the two:

  1. background-blend-mode: luminosity creates different results depending on the darkness or lightness of the initial color: if an icon is completely black, it has no effect at all, while filter: contrast(0) will wipe every color in the original to a medium grey.
  2. Importantly, that includes white; you have to be careful in distinguishing between something that is transparent in the image or if it is filled with white, as it makes a substantial visual difference when applying filter: contrast.
  3. background-blend-mode requires the addition of a background-color for the element, which may not work for all designs.

As they are under 1K, it will probably be worthwhile to inline the SVG icons with DataURI, another advantage of this technique. Explore the code for both examples on CodePen

This site helps millions of visitors while remaining ad-free. For less than the price of a cup of coffee, you can help pay for bandwidth and server costs while encouraging further articles.