Tuesday, April 10, 2012

Truly Responsive CSS Sprites

I've had this nagging issue for some time now with principles versus reality.  Mobile first is the future of design, so I've done my best to adopt responsive principals.  I also work as part of an SEO team, so those principals are incredibly important as well.  One of the things that keeps me up at night is the use of small images on designs.  Designers want them all over the place, SEO says performance matters (a lot!), so the long held solution was sprite maps.  But, sprite maps help performance but have typically been implemented using background images, so we lose out on the juicy SEO value of alt tags and the actual value of the img tag itself.  Possible solution?  Just use the img tag and css clip.  Now comes along responsive design, and I've seen a number of partial solutions that don't satisfy all of the previously mentioned needs, hence this post.  I've put together a solution that satisfies all of the above conditions with some basic css trickery.

The approach can be detailed as such, create your sprite map, use a wrapping div with hidden overflow, and then use an img tag with nothing but percentage based widths and margins and you have yourself a responsive SEO friendly sprite map.  One important detail that I have experienced is that as the image scales to very small levels, then top and bottom percentages get a little off.  One potential workaround if this is a problem is to add some transparent padding at the top and bottom of each block.  My example does not, so you will see a little bit of sprite bleeding.  Now the html / css:


<div class="responsive-sprite" style="width: 5%;">
<img alt="Yay for alt tags..." src="your-pic.png" />
</div>
<style>
img {
 width: 100%;
 margin-top: -96%;
 margin-bottom: -391%;
}
.responsive-sprite {
 overflow: hidden;
}
</style>

Which produces the result:

Yay for alt tags


As always questions and feedback are welcomed and I'll be sure to update with anything else I learn!

UPDATE: After several comments and time/help from a coworker.  We were able to figure out a computational way to determine the percentages.  It turns out that it is:

 (sprite-height / sprite-width) * -100 = Base Percentage

Then for margin-top, it is the (nth - 1 sprite) * Base Percentage.

The for margin-bottom it is (sprite_count - nth_sprite) * Base Percentage.

Hope that works for everyone!