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!

10 comments:

  1. Hey there,
    first, great method. I also need to use responsive sprites, and this looks like the best method I found up to now, and the easiest. However can you give an example of fixing the sprite bleeding ?
    Have you found any other issues with it ?

    Thanks a lot !

    ReplyDelete
    Replies
    1. I have noticed some bleeding happen, and I don't have a fix yet, but my workaround has been to add some padding between the sprites so you just get your transparent sprite background (or any color you use) bleeding in.

      Delete
    2. Thanks for your reply.
      But how do you set the padding so it is really "responsive". E.g. that when changing windows size (or sprite size) it still looks right.
      I would much appreciate if you could give a real-life example (maybe over jsfiddle or something like that).
      Thanks !

      Delete
    3. I added a second image above and added some JS that makes the blog template here flexible on this post. In the rush my image lost it's transparency for some reason, so imagine the white background was transparent or whatnot. The padding I spoke of is done in the image itself (and not the css) to space out the headshots a little more. You'll see when it gets smaller where the green bleeds in on the top image vs. on the bottom where you would just have the empty spacing I added. Make sense?

      Delete
  2. Can you explain the logic behind the numbers you chose as percentages? I love this setup and I'm testing it myself with my own project. I'm setting up a responsive slideshow, and I'd love to use JS to configure the percentages. However, I can't figure out the math behind the percentage/image ratio for the life of me. I just tweak the numbers in Chrome developer tools until it looks right, but I have no idea what the relationship is between the figures.

    ReplyDelete
    Replies
    1. Unfortunately, I haven't had the time to get the exact logic behind how to calculate those percentages. Basically I've taken the same approach you have and just screwed around until it looks right. When I have some time I'd like to get this aspect figured out.

      Delete
  3. I tried several other aproaches without success to maintain some images responsive after making sprites of them. This worked very fine with my bootstrap responsive site. THANK YOU!

    ReplyDelete
    Replies
    1. I'm so glad to hear that this help you!

      Delete
  4. I think I've come up with a solution that might actually require a lot less html markup and might work a little better with more cross-browser support. Basically it just requires using a div with a background image that resizes and moves in the hover state. All that's required in the html is a div with a class. I've actually got a working demo of it over at my blog. The only downside might be that there is no alt-tag on the image, so perhaps diminished SEO value? I'm not sure!

    The demo, with explanation, can be found here: http://blog.brianjohnsondesign.com/2013/how-to-use-responsive-background-image-sprites-css-tutorial/

    ReplyDelete
  5. I have adapted this approach for sets of heterogeneous sprites with arbitrary positions in the atlas: https://gist.github.com/Malkyne/9492320

    You can see it in action at the codepen linked from that Gist.

    ReplyDelete