CSS Dryer

Eliminate Repetition In Your Stylesheets

Introduction

Cascading style sheets (CSS) are wonderful but repetitive. Rails strongly discourages repetition, the don’t repeat yourself (DRY) principle, so writing CSS feels ungainly in Rails.

There are two sources of repetition in CSS:

  • nested selectors
  • lack of variables

Nested selectors lead to CSS like this:

div           { font-family: Verdana; }
div#content   { background-color: green; }
div#content p { color: red; }

Note the triple repetition of div and the double repetition of #content.

The lack of variables leads to CSS like this:

.sidebar { border: 1px solid #fefefe; }
.content { color: #fefefe; }

Note the repeated colour #fefefe.

The CssDryer eliminates both of these sources allowing you to write DRY, pleasing stylesheets. The examples above become:

<% dark_grey = '#fefefe' %>
div {
  font-family: Verdana;
  #content {
    background-color: green;
    p { color: red; }
  }
}
.sidebar { border: 1 px solid <%= dark_grey %>; }
.content { color: <%= dark_grey %>; }

Note, though, that @media blocks are preserved. For example:

@media screen, projection {
  div {font-size:100%;}
}

is left unchanged.

The original whitespace is preserved as much as possible.

See CssDryer for more details.

Which Selectors Are Supported?

The CssDryer handles nested descendant, child, adjacent, class, pseudo-class, attribute and id selectors.

Multiple comma separated selectors are now supported.

Installation

Install in the usual Rails way. From your application’s directory:

script/plugin install http://opensource.airbladesoftware.com/trunk/plugins/css_dryer
Usage

Create a controller to serve your DRY stylesheets:

script/generate controller stylesheets

You don’t have to call it stylesheets but doing so lets you use Rails’ stylesheet_link_tag helper.

Edit the controller so it looks like this:

class StylesheetsController < ApplicationController
  before_filter :set_headers
  after_filter  { |c| c.cache_page }
  session :off
  layout nil
end
private
def set_headers
  ::ActionController::Base.page_cache_extension = '.css'
  headers['Content-Type'] = 'text/css; charset=utf-8'
end

Add this line to your routes in config/routes.rb (note the full stop immediately after the word action):

map.connect 'stylesheets/:action.:format', :controller => 'stylesheets'

You can then put your stylesheets, DRY or otherwise, in app/views/stylesheets/. Once rendered they will be cached in public/stylesheets/.

DRY stylesheet files should have a ncss extension—think ‘n’ for nested. For example, site.ncss.

Get them in your views with a css extension like this:

or with Rails’ stylesheet_link_tag helper:

<%= stylesheet_link_tag 'site' %>
To Do
  • Make set-up easier by instantiating the controller and adding the route dynamically within init.rb. See Corey Johnson's code and Miles Byrne's DCSS respectively.
  • Split out a separate EXAMPLES document.
Alternatives
  • RCSS[http://rubyforge.org/projects/rcss]: ERB, server-side constants, server-side classes and command line execution. No nesting as such, though server-side classes offer a form of inheritance.
  • DCSS[http://rubyforge.org/projects/dcss] (written up here[http://myles.id.au/2006/11/20/introducing-dcss/]): server-side constants, different syntax. Descendant selectors only.
  • Styleaby[http://topfunky.net/svn/plugins/styleaby/README]: creates CSS with Ruby syntax. “An experimental, unauthorized mashup of Scott Barron’s stillborn Builder::CSS templates and Why The Lucky Stiff’s Markaby templates.”
  • {Dirt Simple .rcss Templates}[http://blog.hasmanythrough.com/2006/3/23/dirt-simple-rcss-templates] by Josh Susser. No nesting, just variables.
Credits

The idea came from John Nunemaker on {Rails Tips}[http://railstips.org/2006/12/7/styleaby-css-plugin/]. John beta-tested the code, provided a test case for @media blocks and suggested the controller's body. Thanks John!

The caching code is based on Topfunky's[http://topfunky.net/svn/plugins/styleaby/lib/stylesheets_controller.rb].

Changing the controller's name to stylesheets, thus allowing one to use Rails' stylesheet_link_tag helper, occurred to me while reading Josh Susser's {Dirt Simple .rcss Templates}[http://blog.hasmanythrough.com/2006/3/23/dirt-simple-rcss-templates]. Once I noticed it, I realised everybody was using a StylesheetsController. Doh!

Author

{Andrew Stewart}[mailto:boss@airbladesoftware.com], {AirBlade Software}[http://airbladesoftware.com]

== Licence

CssDryer is available under the MIT licence. See MIT-LICENCE for the details.

Copyright© 2006 Andrew Stewart

Tags

Currently tagged with: css
You need to Login to tag this item.