Sprites and CSS Pseudo-Elements: The Perfect Pair

Posted 3 years ago by Rick Harris

At this point, we all know why spriting is important. And if you’ve used the technique in a few real world projects, you also probably know they can be a pain. The most flexible approach (at least in the short-term) is to use empty span elements wherever you need an icon, then style those up with CSS. Of course, that’s not semantic at all and could become hard to maintain. If you go the semantic route and use CSS exclusively for your spriting needs, you quickly realize that you need to very carefully construct your sprite map lest your images interfere with each other. Then, when you find out you need to add a few icons to the sprite, you cry.

The good glorious news is that it’s possible to have the best of both worlds by using CSS pseudo elements.

An Example

Pseudo elements aren’t really a new thing, so you may already be familiar with them. Or, if you need to brush up, go watch CSS-Trick’s screen cast about pseudo elements. Otherwise, let’s walk through an example to prove that using pseudo elements for spriting is a fantastic idea.

Let’s say we’re styling a link to our Facebook page, and we want to make it real pretty by putting an icon next to it. Our markup is:

<a class="fb-link" href="http://facebook.com/awesome-fb-page">
  Facebook
</a>

Great. Going the semantic route, this is where we style our link using a sprite map as its background with something like this:

.fb-link {
  padding-left: 20px;
  background: (my-great-sprite-map.png) no-repeat 0 -16px;
}

And with any luck, that works well, and no other images in the sprite map interfere with our Facebook link. But without luck, there’s a good chance that the other images directly surrounding our Facebook icon will show up uninvited to this party. So, instead, let’s take the non-semantic route, and add an empty span into the mix:

<a class="fb-link" href="http://facebook.com/awesome-fb-page">
  <span class="icon"></span> Facebook
</a>

This is easy to style and, at least from a CSS perspective, doesn’t suffer from the same downsides as the previous approach does.

.fb-link .icon {
  display: inline-block;
  width: 16px;
  height: 16px;
  background: (my-great-sprite-map.png) no-repeat 0 -16px;
}

But adding empty HTML elements just to style them with CSS is pretty ugly, so let’s do exactly what we did with the empty span, but with a pseudo element instead.

.fb-link:before {
  content: '';
  display: inline-block;
  width: 16px;
  height: 16px;
  background: (my-great-sprite-map.png) no-repeat 0 -16px;
}

The only difference is the addition of content: '';. That’s because pseudo elements won’t render unless the content property is set, even if to an empty string. Now we have semantic goodness and all the benefits an empty span gives us.

I’ve put together a demo page so you can see this example in action. It's a very simple example, but the technique can be used for much more complex styling. And the best part is, for every HTML element, you get two pseudo elements!

Pseudo elements don’t work even a little in IE7 and below. For some of us, that could definitely be a dealbreaker. Just use discretion. There are always situations where it’s appropriate to let IE7 users have a slightly degraded experience; just ask your friend and mine border-radius.

Taking it Further

8 Comments

Kevin Dees ~ 3 years ago

Dude great post. I have not thought about using this for sprites before. However as you point out IE7 and below have really put a stopper in the sweat ideas behind pseudo elements.

Rick Harris ~ 3 years ago

Yeah, the fact that there isn't really a good fallback for IE7 is a bummer.

There's such good fallback options for other newer CSS stuff, though, that I've found myself using images almost exclusively for icon-style things and CSS for everything else. And usually I don't lose too much sleep at night if IE7 users don't get to see a decorative icon.

Kevin Dees ~ 3 years ago

You know, I might just start using this plugin for the whole mess. Too may cool things I'm passing up because of IE

http://jquery.lukelutman.com/plugins/pseudo/

Rick Harris ~ 3 years ago

It'd be nice if there was a polyfill that transparently supported pseudo elements. I'm not in love with the way that plugin makes you write extra and pretty different CSS.

Kevin Dees ~ 3 years ago

Sounds like a project for the week... I'll link it to you when I'm done :D

Nicolas Gallagher ~ 3 years ago

Hi Rick, you might be interested in an article I wrote about this and other CSS background-image hacks using pseudo-elements: http://nicolasgallagher.com/css-background-image-hacks/

Kevin Dees ~ 3 years ago

ok Rick my man here you go. I decided to stay up late tonight and bang it out, enjoy!

https://github.com/kevindees/ie7_pseudo_elements

Needs testing and what not but it works as long as you don't use a select with : in it (outside of after or before). will git that fixed later though.

Lelala ~ 1 year ago

*Again* IE is the dealbreaker :-(
According to GoogleAnalytics, IE7 is still somehwat ~20%, depending on which country you are looking.
Unfortunately, does something like ModernizerJS help here, maybe?

For reservations, call office(800) 890-1702. Send fan mail to our work location at 2 North Main Street, Greenville, SC 29601-2719 USA 34.850823 -82.398746
Lovingly crafted by orangecoat with some rights reserved, and a promise not to spam you.

Back to top