Skip to content

Instantly share code, notes, and snippets.

@thulstrup
Created March 20, 2012 19:18
Show Gist options
  • Save thulstrup/2140082 to your computer and use it in GitHub Desktop.
Save thulstrup/2140082 to your computer and use it in GitHub Desktop.
Using Compass to generate normal and retina sprite maps
$sprites: sprite-map("sprites/*.png");
$sprites-retina: sprite-map("sprites-retina/*.png");
@mixin sprite-background($name) {
background-image: sprite-url($sprites);
background-position: sprite-position($sprites, $name);
background-repeat: no-repeat;
display: block;
height: image-height(sprite-file($sprites, $name));
width: image-width(sprite-file($sprites, $name));
@media (-webkit-min-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 3/2), (min-device-pixel-ratio: 2) {
// Workaround for https://gist.github.com/2140082
@if (sprite-position($sprites, $name) != sprite-position($sprites-retina, $name)) {
$ypos: round(nth(sprite-position($sprites-retina, $name), 2) / 2);
background-position: 0 $ypos;
}
// Hard coded width of the normal sprite image. There must be a smarter way to do this.
@include background-size(444px auto);
background-image: sprite-url($sprites-retina);
}
}
// Usage.
.mail-icon {
@include sprite-background(mail);
}
@AdamBrodzinski
Copy link

Just an FYI for anyone else looking to use this with a hover state, I've forked a version of this from @rstacruz and added hover and active states.
The the mixin with a demo and docs is available here: https://github.com/AdamBrodzinski/Retina-Sprites-for-Compass , as well as the mixin below.

@import "compass/utilities/sprites";         // Include compass sprite helpers
@import "compass/css3/background-size";      // Include helper to calc background size


@mixin sprite($name, $hover: false, $active: false) {
  @include retina-sprite($name, $sprites, $sprites2x, $hover, $active);
}

// The general purpose retina sprite mixin.
  //
  //    @include retina-sprite(name, $spritemap1, $spritemap2)
  //    @include retina-sprite(name, $spritemap1, $spritemap2[, $dimensions: true, $pad: 0])
  //
  //    If `dimensions` is true, then width/height will also be set.
  //
  //    if `pad` is non-zero, then that's how much padding the element will have (requires
  //    $spacing on the sprite maps). Great for iPhone interfaces to make hit areas bigger.
  //
@mixin retina-sprite($name, $sprites, $sprites2x, $hover, $active, $dimensions: true, $pad: 0) {  
  @if $dimensions == true {
    @include sprite-dimensions($sprites, $name);
  }
  background-image: sprite-url($sprites);
  background-position: sprite-position($sprites, $name, -$pad, -$pad);
  background-repeat: no-repeat;

  @if $hover == true {
    $name_hover: $name + _hover;
    &:hover {
      background-position: sprite-position($sprites, $name_hover, -$pad, -$pad);
    }
  }
  @if $active == true {
    $name_active: $name + _active;
    &:active {
      background-position: sprite-position($sprites, $name_active, -$pad, -$pad);
    }
  }

  @if $pad > 0 {
    padding: $pad;
  }

  @media (-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (min-device-pixel-ratio: 1.5) {
    & {
      $pos: sprite-position($sprites2x, $name, -$pad * 2, -$pad * 2);
      background-image: sprite-url($sprites2x);
      background-position: nth($pos, 1) nth($pos, 2) / 2;
      @include background-size(ceil(image-width(sprite-path($sprites2x)) / 2), auto);
      //  sprite-path() returns the path of the generated sprite sheet, which
      //  image-width() calculates the width of. the ceil() is in place in case
      //  you have sprites that have an odd-number of pixels in width

      @if $hover == true {
        $name_hover: $name + _hover;    // create myButton_hover and assign it
        &:hover{
          $pos: sprite-position($sprites2x, $name_hover, -$pad * 2, -$pad * 2);
          background-position: nth($pos, 1) nth($pos, 2) / 2;
        }
      }
      @if $active == true {
        $name_active: $name + _active;    // create myButton_active and assign it
        &:active{
          $pos: sprite-position($sprites2x, $name_active, -$pad * 2, -$pad * 2);
          background-position: nth($pos, 1) nth($pos, 2) / 2;
        }
      }
    }
  }
}

@estahn
Copy link

estahn commented Oct 5, 2012

Is there any way we can not add media queries on each individual icon class on compiling? Not sure if there's a different way to go about this fix.

I wondered the same thing. This is what i came up with: https://gist.github.com/3837343

@tegola
Copy link

tegola commented Jan 2, 2013

Do somebody have a fix for the long compile time mentioned by @bakura10? I'm using compass on a Sencha project with about 30 sprites, and while the "compass compile" takes from 15 to 20 seconds to finish – and I can see it trying to generate sprites multiple times – Sencha's build command takes forever.

@AdamBrodzinski
Copy link

@tegola , not sure it this is related but you may want to checkout this issue.

@nathansh
Copy link

I've had issues with the retina sprite when using smart layout. I tried to use smart layouts as follows:

$sprites-retina: sprite-map("double/*.png", $layout: smart);

This resulted in two identical sprite images as expected, but SASS wasn't calculating the distances properly at all.

@yahreen
Copy link

yahreen commented Apr 8, 2013

I am having issues with $layout: smartas well. Anyone have a fix?

@jessicaldale
Copy link

Anyone get '$layout: smart' working? Also, is anyone using this with images of varying sizes/dimensions? I want to create a sprite that contains all of my site's ui elements, but they aren't all square shaped.

@eprothro
Copy link

eprothro commented Nov 4, 2013

We prefer using the compass helpers for sprite map and style class generation. This is a bit more future proof than manually setting background-size as well as less labor intensive than generating the style classes manually:

Compass Retina Spriting

@heidmotron
Copy link

@thulstrup Can you include an open source license in this gist?

@brewster1134
Copy link

here is my take on retina sprites. i wanted a way to use it within the @media directive as well...

https://gist.github.com/brewster1134/13162e2cb0220e87b017

I would love some feedback...

@mbilalsiddique1
Copy link

Here is my try to make it little short and for best practice. I wanted to use background-image property for once instead of using it in every class to minimise my code. I make this
https://github.com/mbilalsiddique1/Sass-Mixins

@import "compass/utilities/sprites";         // Include compass sprite helpers
@import "compass/css3/background-size";      // Include helper to calc background size

// General Sprite Defaults
// You can override them before you import this file.
$icon-sprite-base-class: ".icon-sprite" !default;
$icon-sprite-dimensions: false !default;
$icon-spacing: 10px !default;
$icon-position: 0% !default;
$icon-repeat: no-repeat !default;

$icon-sprites: sprite-map("sprites/*.png", $spacing: $icon-spacing, $repeat: $icon-repeat, $position: $icon-position);
$icon-sprites-retina: sprite-map("sprites-retina/*.png", $spacing: $icon-spacing * 2, $repeat: $icon-repeat, $position: $icon-position);

// All sprites should extend this class
// The icon-sprite mixin will do so for you.
#{$icon-sprite-base-class} {
  background: $icon-sprites $icon-repeat;
}

@media (-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3 / 2), (min-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx) {
  #{$icon-sprite-base-class} {
    background: $icon-sprites-retina $icon-repeat;
    @include background-size(ceil(image-width(sprite-path($icon-sprites-retina)) / 2) auto);
  }
}

// Extends the sprite base class and set the background position for the desired sprite.
// It will also apply the image dimensions if $dimensions is true.
@mixin icon-sprite($name, $dimensions: $icon-sprite-dimensions, $offset-x: 0, $offset-y: 0) {
  @extend #{$icon-sprite-base-class};
  @include sprite($icon-sprites, $name, $dimensions, $offset-x, $offset-y)
}

// Example Usage.
.icon-analytics {
    @include icon-sprite(main-sprite);
}

@tomasdev
Copy link

My smaller contribution: https://gist.github.com/tomasdev/56bc62e86ab0700f8298 works right out of the box if you're planning to save only the biggest assets and not the pixelated (non-retina) ones.

@mgarabedian
Copy link

@mbilalsiddique1 - thanks for this bit above. Working well for my usage thus far. Maybe i missed it, but any way to have the css for all icons in the folder automatically render with their unique file names as classes, instead of defining each one again ( as you show in your example ) ?

// Example Usage. .icon-analytics { @include icon-sprite(main-sprite); }

@mgarabedian
Copy link

I believe i figured it out how to declare all the sprites in the map. Works well on top of whats above.

$sprite-names: sprite_names($icon-sprites);
@each $sprite in $sprite-names {
    .icon-#{$sprite} {
      @include icon-sprite($sprite, true);
    }
} 

@julkue
Copy link

julkue commented Jul 9, 2015

How to combine this mixin to get the image height of the sprite?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment