Where’s Your Assets?

Damn! I’m hard coding all the project imagery assets within my stylesheets. What if the url to those image assets change? This is where Compass will come to the rescue.

To be completely frank, I almost completed an entire bowel movement upon discovery of this sneaky little helper I’m going to discuss. The story goes like this; work locally with your assets folder, upload your code and assets to the deployment server, test, and then finally make it production ready, but we’re missing one important aspect from this entire process; What happens if the location of those assets change –or– worse they’re moved to a cdn? Now you’ve gotta sift through hundreds, or even thousands of lines of code and swap out the url. Have no fear though as we can solve this problem in a non–trivial manner using a special compass helper called image-url.

Before I found the image-url helper I was doing the following…

$assets_path: "http://example.com";
background: url(#{$assets_path}/img/logo-sprite.png) -277px 0 no-repeat;

Figure 1

Executing the method in Figure 1, I only had to change the $assets_path and call it a day, but that’s not good enough yet. Compass can do way better than my silly Sass variable. This approach only works if your images always rest within an img directory, but it’s flawed for that very reason.

Lets take a look at the following examples to get a better understanding of this mysterious beast called image-url.

Compass Config

# Set this to the root of your project when deployed:
http_path = "/"

# Set the images directory relative to your http_path or change
# the location of the images themselves using http_images_path:
# http_images_dir = "assets/images"

# Production Assets URL
http_images_path = "http://your-url-goes-here/img"

css_dir = "/"
sass_dir = "scss"
images_dir = "img"
javascripts_dir = "js"

output_style = :expanded
environment = :development

relative_assets = false

line_comments = false
color_output = false

Figure 2

Using our config.rb example above we’re including two very important helpers http_images_path & relative_assets. Setting the value for http_images_path will direct all your image assets to your production server, CDN or any other dark closet you’re hiding things in. It can also generate cache–busting query strings based on image timestamps. This will keep browser caches from displaying the wrong image if you change the image but not the url. If you don’t want this behavior, it’s easy to configure or disable.

Say I want to keep my images on a sub–domain, then all I would do is change the path like so…

http_images_path = "http://static.mysite/img/"

Figure 3

and then in our .scss file…

// bring compass into our project
@import "compass";

// image-url() example.
// Compass will automatically generate a relative URL to the file.
background: image-url("logo-sprite.png") -277px 0 no-repeat;

Figure 4

This will direct all my assets to the URL I’ve defined for http_images_path…Hot Damn! that’s some sweet sauce. I could take this one step further and set the relative_assets line to true while working locally like so;

relative_assets = true

Figure 5

relative_assets will now serve all the assets from your local assets/images directory that’s defined by your config.rb file seen in Figure 6:

# Project Assets Location
css_dir = "/"
sass_dir = "scss"
images_dir = "img"
javascripts_dir = "js"

Figure 6

Pretty rad huh? we can also use a relative url based on our http_path

# Set this to the root of your project when deployed:
http_path = "http://your-url-goes-here.com/path-to-your-directory/"

# Set the images directory relative to your http_path or change
# the location of the images themselves using http_images_path:
http_images_dir = "img"

# Production Assets URL
# http_images_path = "http://your-url-goes-here/img"

css_dir = "/"
sass_dir = "scss"
images_dir = "img"
javascripts_dir = "js"

relative_assets = false

Figure 7

Although this method works just fine I prefer to use http_images_path and call it a day. Now that you have this nifty Compass helper down why not optimize those images and read my article on optimizing images with Grunt. As always, hit me up with any questions, comments, suggestions or rants.

Your links

Dennis Gaebel

Design Technologist, fly fisherman and guitar shredder making stuff out of browser native technologies. Co-Pilot for Open Source projects like Typeplate (Smashing Magazine Feature) and the A11YProject. Helper Bee at CSS-Tricks and Happy blogger for Web Design Weekly. Owner at Gray Ghost Visuals. Say hi to me on Twitter.
  1. ❧ A. Tate Barber shouted:
    2012/12/12 • 7:00 am

    Thank you so much for this! I have been working on a goal to create my perfect development environment for WordPress themes with the help of Compass. Needless to say, I have lost a few hours of sleep over figuring out this config.rb flow. This post helped me immensely with the problem of using Compass helpers (specifically image-url() ) on a WordPress child theme when the theme directory is contained in a deep directory or when the CSS directory is in a different location than the root of a theme directory. Thanks for the tips! Great post!

    1. Thanks Tate! Glad to have helped. It’s gotta be one of my top five favorite compass helpers. Cheers!

  2. ❧ Kris Frenz shouted:
    2013/08/22 • 1:44 pm

    Thank you for sharing your knowledge. I was just wondering if it was possible to have different images directories for different css files to keep things organized. Let’s say I’m using xyz.scss that uses a sprite.png file and another abc.scss that will use its own sprite.png. with a structure like this: XYZ/img/sprite.png / XYZ/xyz.css. Same for ABC. So I can use relative paths (image-url(sprite.png or arrows.png)) on each SCSS without being specific about the location. Then I use Compass to watch these files so I can get a compressed output. I hope you can understand my question. Each SCSS or CSS uses lots of images that if we just dump to the images_dir="img" directory it looks like a big mess. Prefixing each .png could be a solution but it’ll be cleaner to have separate img/ folder for each css.

    1. Hey Kris! Good question. Good enough in fact that I decided to ask the man himself. https://twitter.com/chriseppstein/status/370585253720510465

      The good news is that the next release of Compass will have this ability!

  3. ❧ Drew shouted:
    2013/08/28 • 6:25 pm

    It would be nice if this function worked when the path and directory don’t match up. For instance, /mobile/img/image.png was served from /img/image.png.

    1. Man that’s a crazy situation right there. I see that mostly in situations with markup and not the actual style sheet URI’s. In the case of using Compass’ image-url that would be an easy fix. Just redefine your img directory or even rename it if you’d like.

  4. This is the fourth or fifth time I’m referring to this article for help – thanks a ton! On a completely nonconstructive note, calling the article “Cover your ASSets” would be funny…at least I thought so. Thanks again dude!

  5. Super helpful article, didn’t know about the relative assets function. Thanks!

  6. Forgot to tack on.. is it possible to store the image_url result in a variable? For example:

    // variables.scss
    $banner-img: image_url(banner-img.jpg); 
    
    // component.scss
    .banner {background: url($banner-img);}

    Doesn’t seem to work, but would definitely improve the workflow.

  7. ** Totally works, messed up a dash

  8. ❧ Ethan shouted:
    2014/09/12 • 1:53 am

    Trying to get things set up to be able to use Sass and Compass on my pet project (using clojure & pedestal) to do CSS as intelligently as I know how and finding how to get the correct images directory outputted was evading my grasp for far longer than I’d care to admit. Images showing up now and I can’t get the smile off my face :)

    1. That is awesome Ethan. This helper is pretty much the main reason I stick with Compass still.

  9. ❧ Nikola shouted:
    2014/10/13 • 1:59 pm

    If you don’t need the cache-buster, you don’t need to use Compass. All of this can be accomplished by writing a pure Sass function…

    
    $http_path: "http://your-url-goes-here.com/path-to-your-directory/";
    $http_images_path: "img/";
    
    @function image-url($relative-url){
      $tmpUrl: $http_path + $http_images_path + $relative-url;
      @return url($tmpUrl);
    }
    

    Then you can use it like so:

    
    div {
       background-image: image-url('some_back.png');
    }
    
    1. Awesome Snippet Nikola for non Compass users. Thanks for the tip.

  10. ❧ Jon shouted:
    2014/10/18 • 12:05 am

    How would I go about when I have the project images organized in folders inside img like:

    img/blog
    img/pages
    img/fallbacks

    I’m guessing something like this?

    background: image_url("fallbacks/banner-img.jpg");

    Rendering:

    background: url(../fallbacks/banner-img.jpg);

    But it doesn’t work for me, I get:

    background: url(/fallbacks/banner-img.jpg);
    1. This ability was supposed to be in the 1.0 release, but it got pushed back by Chris. Look for it to be available hopefully in the 1.1 release.

Leave a Reply

Your email address will not be published. Required fields are marked *

show formatting examples
<pre class="language-[markup | sass | css | php | javascript | ruby | clike | bash]"><code>
…code example goes here…
</code></pre>

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Comment Preview

  1. John Doe shouted this comment preview:
    2012/10/05