Responsive Sprites With SASS And Compass

I came across an interesting problem over the weekend and I thought it might be a good idea to share my solution. I was working on a site using SASS plus Compass and I had a number of images that I needed to set up as sprites in order to increase page load performance.

Setting up sprites with Compass is normally very easy. You simply add your sprite .png files to a directory within your project’s assets directory and point your config.rb file there with the following line: images_dir = "assets".

For the purpose of this post, let’s say that your sprite assets have the following paths:

  • assets/icons/new.png
  • assets/icons/edit.png
  • assets/icons/save.png
  • assets/icons/delete.png

Once you’ve placed your icons and set your config.rb file correctly, you simply create a new SASS partial called _sprites.scss and add the following three lines:

@import "compass/utilities/sprites";
@import "icons/*.png";
@include all-icons-sprites;

This will give you the following classes, which you can then apply to your site’s markup:

.icons-sprite,
.icons-delete,
.icons-edit,
.icons-new,
.icons-save   { background: url('/images/icons-s34fe0604ab.png') no-repeat; }

.icons-delete { background-position: 0 0; }
.icons-edit   { background-position: 0 -32px; }
.icons-new    { background-position: 0 -64px; }
.icons-save   { background-position: 0 -96px; }

This is a great feature of Compass, but it falls short for responsive sites that need fluid-size sprites. On my project, I needed sprites that would resize to fill their fluid size containers. I did some digging, and ended up coming up with the following mix-in. Simply add this mixin to your _sprites.scss file and then use it within a selector for the container element. Here’s the mixin:

@mixin responsive-sprite($map, $icon) {
  $icon-file: sprite-file($map, $icon);
  $icon-width: image-width($icon-file);
  $icon-height: image-height($icon-file);

  $sprite-file: sprite-path($map);
  $sprite-map: sprite-url($map);

  $sprite-width: image-width($sprite-file);
  $sprite-height: image-height($sprite-file);

  $space-top: floor(nth(sprite-position($map, $icon), 2));
  @if $space-top == 0 {
    $space-top: 0px
  }

  width: percentage($sprite-width / $icon-width);
  display: block;
  height: 0;
  padding-bottom: percentage($icon-height / $icon-width);
  background: $sprite-map;
  background-size: 100%;
  background-position:0 percentage(-1 * $space-top / ( $sprite-height - $icon-height ) );
}

Once you have this in place, you can use it as such:

.my-sprite-wrapper-div {
  @include responsive-sprite($icons-sprites, save);
}

And voila, you now have responsive sprites which are auto-generated for you by Compass.


Further reading: