Working with Compass Sprites

In a recent web app, my team decided to try Compass sprites to make our lives easier. Here’s a note from the Compass sprite description:

Spriting has never been easier with Compass. You place the sprite images in a folder, import them into your stylesheet, and then you can use the sprite in your selectors in one of several convenient ways.

Sounds like a time and worry-saver to me! I’d like to take advantage of all it has to offer. However, it didn’t work as easy as it sounded. The problem comes in being able to tweak the positioning after Compass has done its work. This is an account of what I tried and the problems I encountered from a design perspective.

Why CSS sprites are useful

I like to create sprites in my web pages to reduce the number of hits the browser needs to make to the server. I do this on an ad-hoc basis, depending on the size of a page, or where there might be an unacceptable response time on load. Fewer images means easier to manage, use and reuse.

Normally, I manually create the sprite and measure each icon to get its position for placing it properly the CSS. This can be time-consuming, but offers flexibility with spacing.

  1. Gather all the icons/images into one Photoshop file
  2. Measure each icon by hand to get coordinates
  3. Put coordinates in CSS to position the background

Adding spacing can help with design

Sometimes, from a design perspective, it’s nice to add extra space above or below the image to push the image up or down, depending on the layout. I usually do this in the CSS by positioning the coordinates in the background settings.

For instance, I wanted to push the green arrow down a couple pixels to weight its balance with the title text. The containing element (an H2) is the same height as the image. If I add 2 pixels to the y-axis, it will push it down to nicely balance it in the design.

h2 {
  background: url('icons/arrow-left-dark-green.png') no-repeat 10px 2px
}

But, there’s got to be a way to make sprites easier to create and manage.

What Compass sprites has to offer

In general, Compass makes my life a lot easier while front-end coding because it takes away a lot of headaches making sure I’ve covered every scenario for code cleanliness, reusability, compatibility and more. Combined with Sass, it makes for a lot of efficiencies and less worrying while coding.

Compass also makes spriting easier, taking all the fussing over details away. In order for Compass to pull this off, it combines all the images into one file (sprite), and keeps track of where it is in the sprite. Then, the Compass mix-in in the Sass (see example below) moves the position automagically in the generated CSS.

Wait, Help!

With my scenario above, using Compass sprites poses a problem. Compass knows nothing about my extra 2 pixels of space added to the y-axis. So, it places the image in the top-left of the containing element (the h2) on the web page. As far as I can tell, there’s not a way to add 2 pixels after the fact to reposition my image the way I want it.

@import "icons/*.png";

h2 { @include icons-sprite(arrow-left-dark-green); }

(See more about how to use Compass sprites in your CSS on the Compass spriting tutorial)

I want more control

What I would love to be able to do is modify the Compass mixin to ADD some positioning to its pre-calculated position. Theoretically, they could just add (or subtract) the pixel count I define to the dimensions it uses.

@import "icons/*.png";

h2 { @include icons-sprite(arrow-left-dark-green, 10px 2px); }

What are my options?

Without the ability to modify the generated CSS, I see a few options for how to solve the problem.

1. Add transparent pixels to the top of my image in Photoshop to push it down.
Compass will then include the extra space in its new image, and I will get the effect I’m looking for in the final design. This takes time and seems contrary to the intent of Compass spriting.

2. Add an extra DOM element inside the header (like a span) and position it inside the containing element in the CSS to be the exact way I want it displayed.
In this method, Compass will do its job by placing the image in the upper left corner of the inside span and doesn’t have to know I’m tweaking the position of the child container in the CSS. This option means I don’t have to modify my image, but is less appealing for the extra markup and CSS it introduces. Not ideal, but does the trick.

3. Keep this image out of the sprite folder that Compass watches.
This option doesn’t use Compass sprites at all but allows me to position the as I originally did in the CSS.

Given our trouble, my team decided to back out for now. When using Compass sprites, how should I approach positioning problems like this?

Conversation
  • Kevin says:

    Hi Paul,

    Found this post via Google.

    In response to your “I want more control”, I dug through the source code thinking that’d be a cool thing to add your “WishfulThinking.css” to Compass but apparently its already included as of v0.11.7.


    @mixin #{name}-sprite($name, $dimensions: $#{name}-sprite-dimensions, $offset-x: 0, $offset-y: 0)

    so just by doing something like:


    h2 { @include icons-sprite(arrow-left-dark-green, $offset-x: 10px, $offset-y: 2px); }

    which would add some extra positioning later on. Not sure why this isn’t documented yet.

  • Paul Hart says:

    Thanks for the info, Kevin! I’ll definitely give that a try.

  • Adam McCrea says:

    I had the same issues. Just posted my solution here.

  • […] a few benefits that improve page load time. This is my second attempt at using Compass Sprites. The first time I tried to implement it, I ran into a problem that caused me to put it down for a while. But the benefits seemed too good […]

  • Nate Kraus says:

    What about:

    h2:before {
    @extend .icons-arrow-left-dark-green;
    content: ”;
    display: inline-block;
    vertical-align: middle; /* Most likely */
    position: relative; /* If moving it up or down is necessary */
    top: 2px; /* or whatever aligns it where you want */
    }

    That works great for me if the h2 (or whatever) is only one line of text. If using it on something that is/might be multiple lines then I use “position: relative” on the h2 and “position: absolute” on the h2:before.

    This way I dont have to manipulate my sprite, which is ideal if the same image is used elsewhere, and I do not have to add extra markup. Let me know your thoughts.

  • Paul Hart says:

    Nate,

    Yeah! That’s another valid solution to the problem of positioning the image. Good call!

    Now that the $offset-x and $offset-y have been introduced, I’ve been using that mostly. However, one benefit to your way, as you said, is easily overriding the positioning if the background is used elsewhere and needs to be adjusted.

    A downside is that :before psuedo element doesn’t work in IE7 without some duct tape and bail wire. But if that’s not a target, or you don’t mind the image not appearing in that browser, it’s okay.

    Thanks for the idea!

    Paul

  • Comments are closed.