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 urls. 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.

config.rb

# Require any additional compass plugins? Uncomment the following line
# require "/Library/Ruby/Gems/1.8/gems/compass-X.XX.X/lib/compass-plugin-name.rb";

# 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"

# Compass will automatically add cache busters to your images 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:
# UNCOMMENT THE NEXT THREE LINES
#asset_cache_buster do |http_path, real_path|
#  nil
#end

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

# Development
output_style = :expanded
environment = :development

# Production
# output_style = :compressed
# environment = :production

# To enable relative paths to assets via compass helper functions Uncomment the following line:
# relative_assets = true

line_comments = false
color_output = false

# If you prefer the indented syntax, you might want to regenerate this
# project again passing --syntax sass, or you can uncomment this:
# preferred_syntax = :sass
# and then run:
# sass-convert -R --from scss --to sass scss scss && rm -rf sass && mv scss sass

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 (see lines 14 thru 20 from Figure 2).

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 uncomment the relative_assets line while working locally like so;

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

# To enable relative paths to assets via compass helper functions uncomment the following line:
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 Line 4 below:

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

Figure 6

Pretty rad huh? we can also use relative urls 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"

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

# To enable relative paths to assets via compass helper functions Uncomment the following line:
# relative_assets = true

Figure 7

Although this method works just fine I prefer to use http_images_path and call it a day. As always, hit me up with any questions, comments, suggestions or rants. Now go and make wonderful relative urls frustration free on your next project.

Your links

  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 helpped 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 sprinte.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

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