Stylish is a tool that lets you generate CSS code with a minimum of fuss. Its aim is to make writing certain kinds of stylesheet much simpler. Common examples include those with a lot of duplication, or which are just variations on the same basic structure.

The following tutorial assumes you have Ruby and RubyGems installed. Ruby programming knowledge helps, but should not be essential.

Why would you want to write CSS in Ruby?

Because CSS doesn’t have loops or variables, and can be very repetitive. Stylish allows you to eliminate a lot of redundancy in your code. There are other reasons too, as we will see throughout this tutorial. For a more comprehensive explication, read Generating CSS with Stylish.

Installing Stylish

The simplest way to install Stylish is via RubyGems:

sudo gem install stylish

Stylish has no gem dependencies. Ruby 1.8 and Ruby 1.9 are both supported, but using 1.9 is recommended since it makes developing with Stylish that bit more pleasant.

Creating simple stylesheets

The foundation of the stylesheet generation DSL is the Stylish.generate method. This takes a block, and returns a Stylesheet object.

style = Stylish.generate do
  # Your rules here
end

Now to construct some rules. This is done with the rule method, which must be passed one or more selectors, a hash of declarations and/or a block.

style = Stylish.generate do
  rule "div.section", :margin_bottom => "1em"
end

Note that selectors are strings, and declarations are hashes where the keys are symbols and the values are strings. The rule method can be a bit verbose, so selectors which consist of a single HTML element can be used directly as methods.

style = Stylish.generate do
  p :line_height => 1.5
  a :text_transform => "uppercase"
end

Rules can also take a block, which creates a new selector scope. This means that rules with repetitive CSS namespacing using descendant and child selectors can be refactored into simple tree structures.

style = Stylish.generate do
  rule "div.section" do
    p :line_height => 1.5
    a :text_transform => "uppercase"
  end
end

style.to_s # => div.section p {line-height:1.5;}
           #    div.section a {text-transform:uppercase;}

Once you’ve created your stylesheet object, you’ll probably want to serialise it to a file. The Stylesheet class includes a print method for just this eventuality.

style.print('my_style.css')

Using variables

Variables allow property values to be determined when the stylesheet is serialised, rather than when it’s declared. A hash (in other words, a symbol table) containing the variables’ names and values should be passed to the stylesheet’s to_s method.

style = Stylish.generate do
  a :color => :bright
end

style.to_s :bright => "f00" # => a {color:#f00;}
style.to_s :bright => "0f0" # => a {color:#0f0;}
style.to_s :bright => "00f" # => a {color:#00f;}

Variables are represented by Ruby symbols, and can be used in place of selectors as well as properties.

style = Stylish.generate do
  rule :wrapper do
    a :color => :bright
  end
end

style.to_s :wrapper => "#wrapper", :bright => "f00"
  # => #wrapper a {color:#f00;}

Variables allow the same simple template to be used multiple times. Creating different colour schemes is the classic use case, but there are plenty of others.

Compound values

Most declaration values are simple strings or numbers. Some, however, have a more complex internal structure. The most common example is background declarations.

style = Stylish.generate do
  body :background => {:color => "fafafa", :image => "bg.png",
                       :repeat => "no-repeat", :position => ["50%", "10px"],
                       :compressed => true}
end

style.to_s
  # => body {background:#fafafa url('bg.png') no-repeat 50% 10px;}

The compressed flag tells Stylish to use the shorthand form of the various background- properties; omitting it will generate the more specific longhand declarations.

body {
  background-color:#fafafa;
  background-image:url('bg.png');
  background-repeat:no-repeat;
  background-position:50% 10px;
}

Variables will work both as a replacement for compound values, substituting the entire hash or array when serialising the stylesheet.

style = Stylish.generate do
  body :background => :bodybg
end

style.to_s(:bodybg => {:url => "/images/eyewatering.gif"})
  # => body {background-image:url('/images/eyewatering.gif');}

However, they can also be used within the body of the compound value, nested as deeply within the data structure as necessary.

style = Stylish.generate do
  body :background => {:color => "000", :image => :fruit}
end

style.to_s({:fruit => "apple.jpg"})
  # => body {background-color:#000; background-image:url('apple.jpg');}

Combining compound values and variables in this way can be very powerful, as often one will only want to make minor changes between different stylesheets, and picking out a particular value with a variable simplifies the mappings between variables and values considerably.

Multiple background images

Stylish attempts to build in forward-compatibility with powerful features of CSS3 such as multiple background images. When using these features in Stylish, two simple rules of thumb should be followed:

  • Singular declarations have singular names and take singular values
  • Multiple declarations have plural names and take arrays of values

To illustrate this, let’s look at two different background declarations.

style = Stylish.generate do
  body :background => {:image => "single.png"}
  rule ".wrap", :background => {:images => ["first.png", "second.png"]}
end

style.to_s # => body {background-image:url('single.png');}
           #    .wrap {background-image:url('first.png'), url('second.png');}

In other words, to give a rule one background image, use :image; to give it several, use :images (and an array of values). This applies to all background properties which may take multiple values:

  • background-image, use :images
  • background-origin, use :origins
  • background-clip, use :clips
  • background-repeat, use :repeats
  • background-size, use :sizes
  • background-position, use :positions

Note that the singular and plural versions are incompatible with one another; if you use :image in a background declaration you can’t use :images in the same declaration, and vice versa.