Read more

Render Sass stylesheets dynamically

Tobias Kraze
November 30, 2012Software engineer at makandra GmbH

If - for whatever reason - you have to render stylesheets dynamically, the following snippet might be of help. It emulates what "sprockets" would to when precompiling your assets, and give your stylesheets access to all the regular bells and whistles (like asset_path, proper @imports etc):

class DynamicStylesheetsController < ApplicationController

    def show
      logical_path = RELATIVE_PATH_TO_YOUR_TEMPLATE
      path = File.join(Rails.root, logical_path)
      template = Sass::Rails::SassTemplate.new(path)
      environment = YourApp::Application.assets
      context = environment.context_class.new(environment, logical_path, Pathname.new(path))
      output = template.render(context)
      render :text => output, :content_type => 'text/css'
    end
    
end

Injecting information

Illustration UI/UX Design

UI/UX Design by makandra brand

We make sure that your target audience has the best possible experience with your digital product. You get:

  • Design tailored to your audience
  • Proven processes customized to your needs
  • An expert team of experienced designers
Read more Show archive.org snapshot

I needed to inject some color values into my stylesheets, and did not want to run everything through ERB first (which is also hard, because of @import statements etc). So I did basically this:

  1. Before the template.render, insert:

    context.singleton_class.send(:define_method, :theme_colors) do
      HASH_OF_COLOR_VALUES # e.g. { 'primary' => [100, 250, 10] }
    end
    
  2. In an initializer, add

    module Sass::Script::Functions
      def color(color_name)
        assert_type color_name, :String
        context = @options[:custom][:resolver].context
        Sass::Script::Color.new(context.theme_colors[color_name.to_s])
      end
      declare :color, :args => [:string]
    end
    
  3. In your sass template, use something like

    $PRIMARY_COLOR = color(primary)
    

Performance

Sass is not especially fast (and it usually does not have to be). For my medium-sized stylesheet, rendering took about 0.5 seconds. It's probably still a good idea to

  • use some form of action caching or page caching
  • make sure you set proper expiration and cache headers

Caveat

This solution is probably somewhat brittle, since the methods used are not exactly part of a public API. If you know of a cleaner way to do this, please drop me a line.

Tobias Kraze
November 30, 2012Software engineer at makandra GmbH
Posted by Tobias Kraze to makandra dev (2012-11-30 17:28)