Spree Commerce

Try It Now

Sass Stylesheet Refactoring

Posted on May 28, 2009 by steph

This year at RailsConf, I met Chris Eppstein, a core contributor to the Sass project, and the creator of the Compass framework. Having recently integrated Sass, Compass, and Blueprint in the release of Spree 0.8.0, I wanted to have Chris look at the Spree core Sass implementation. He gave some great insight and as a result, several changes were made to the Spree core described below:

First, with the latest core changes, screen.Sass is broken down into several components, such as:


<p>&#8230;<br />
@import mixins.Sass<br />
@import colors.Sass<br />
@import layout.Sass<br />
@import product_detail.Sass<br />
@import cart.Sass<br />
@import checkout.Sass<br />
&#8230;</p>

This improved organization will make it easier to adjust the core code for specific page or component changes. For example, one visitor to the RailsConf Spree Birds of a Feather session discussed how his client requires the single page checkout to be overridden and separated into separate steps. Instead of managing the entire screen.Sass stylesheet, he can simply override the checkout.Sass file for the required changes. This modularization will make it easier to adjust style rules without the fear of conflicting with or breaking other site style rules.

Second, a benefit that comes from the Sass improvements is the move to separate color stylesheet rules from the layout style rules. For example, the colors.Sass file contains the following:


<p>&#8230;<br />
!input_border = #<span class="caps">BBB</span><br />
!default_border_color = #<span class="caps">DDD</span><br />
!link_hover_color = #eee<br />
!lighter_text_color = #666<br />
!medium_blue = #2E6AB1<br />
!lightest_blue = #<span class="caps">BBDAFD</span><br />
!light_blue = #E5F2F8<br />
!dark_blue = #162F54<br />
&#8230;</p>

These color rules are then used throughout the stylesheets. Below is an example of their implementation:


<p>#header<br />
 :position relative<br />
 :color = !medium_blue<br />
 :clear both<br />
 a<br />
   :color = !medium_blue<br />
   &amp;:hover<br />
     :color = !light_blue</p>

The above Sass yields the following css rules:


<p>#header {<br />
 position: relative;<br />
 color: #2e6ab1;<br />
 clear: both; }<br />
 #header a {<br />
   color: #2e6ab1; }<br />
   #header a:hover {<br />
     color: #e5f2f8; }</p>

The benefit of separating the colors from the layout is that the long term plan is to allow for a much easier way to reskin the site by making minimal changes to layout.Sass and colors.Sass. For example, in the future colors.Sass may contain the following:


<p>&#8230;<br />
!input_border = #<span class="caps">BBB</span><br />
!default_border_color = #<span class="caps">DDD</span><br />
!link_color = #<span class="caps">ABABAB</span><br />
!link_hover_color = #<span class="caps">EEE</span><br />
!lighter_text_color = #666<br />
!background_color = #2E6AB1<br />
!accent_color = #<span class="caps">BBDAFD</span><br />
&#8230;</p>

A separation of "lipstick" and "layout" will ease the ability to customize the Spree look, which is an essential for every implementation of Spree.

A final benefit with this round of Sass improvements was to take advantage of mixins, which allow you to define a set of CSS attributes and include them in any number of selectors as an inline rule. This goes along with the DRY notion – it’s much easier to manage a single css definition that is applied to many selectors. The mixins also accept arguments and can have a default argument value. Below is an example of a mixin definition with a default value:


<p>= round_corners(!radius = 5px)<br />
 :-moz-border-radius= !radius<br />
 :-webkit-border-radius= !radius</p>

The mixin is used in a selector, such as:


<p>button<br />
 +round_corners(0.3em)<br />
 &amp;.large<br />
   +round_corners</p>

The above example yields the following CSS:


<p>button {<br />
 -moz-border-radius: 0.3em;<br />
 -webkit-border-radius: 0.3em;<br />
}<br />
button.large {<br />
 -moz-border-radius: 4px;<br />
 -webkit-border-radius: 5px;<br />
}</p>

Although at this point the Sass implementation does not introduce new skinning functionality, it certainly gets the Spree project moving in the right direction. Some future improvements include improving the ease of overriding Spree core colors as discussed above, improving the ease of overriding stylesheet rules or complete Sass components, and introducing a mechanism to include extension style rules in order to avoid having to include a separate stylesheet for every extension.

For more information on Compass and Sass, take a look at the Compass & Sass screencast.