SASS Ruby Extension to Check if File Exists

February 6, 2013 · 2 min read

CSS is executed client-side and so it cannot check for the existence of an image, font or other asset file being referenced. However, since Sass is written in Ruby, it allows for server-side calls by extending Sass via custom functions. Here is a custom function to check for the existence of a file:

module Sass::Script::Functions 
     # Does the supplied image exist? 
     def file_exists(image_file) 
          path = image_file.value 
          Sass::Script::Bool.new(File.exists?(path)) 
     end 
end

If this code is placed in a file named functions.rb, the Sass watch command would be:

sass --watch style.scss:style.css --require functions.rb

So, why would you ever need to check for the existence of a file at Sass compile time? One place I found it useful (I'm sure there are other uses) was when eliminating duplication of internationalized CTA (call-to-action) images. Canadian (or British) English is similar to U.S. English in many ways, but there are some words that are a different between the two (favorite vs favourite for example). The following Sass mixin selects a CTA image from a folder based on the lang attribute set on the page. In the case of Canadian English, it will first check to see if the image exists in the en-ca folder. If not, it will fall back to using the image from the en-us folder. This avoids duplication of the English images that are the same in both Canadian and U.S. English. The benefit of this is:

  1. Fewer total assets, so they are easier to maintain
  2. The total asset payload is smaller (especially important if used in a mobile app)
@mixin localeImage($image: null) { 
     [lang="en-us"] & { 
          background-image: url('assets/img/en-us/#{$image}'); 
     } 
     [lang="en-ca"] & { 
          $file: 'assets/img/en-ca/#{$image}'; 
          @if file_exists($file) { 
               background-image: url('#{$file}'); 
          } else { 
               background-image: url('assets/img/en-us/#{$image}'); 
          } 
     } 
     [lang="fr-ca"] & { 
          background-image: url('assets/img/fr-ca/#{$image}'); 
     } 
}