Sass, Compass, and Assetic in 10 minutes

CSS are boring for most of the developers. They don't like it. They prefer development, because they hate supporting Internet Explorer, they find no pleasure in writing CSS and they are right : CSS is boring. Writing CSS means most of the time repeating code, supporting browsers and creating static code.

There are also the frontend required optimizations, who prevent the developer from generating beautiful and DRY CSS : sprite generation, put all CSS in one file, compress assets, and so on.

Most of the time, they prefer to have a "ready-to-use" HTML production. This approach is not the most optimal, because you need to adapt CSS, to add new rules, to refactor some parts. CSS are part of the application, as the PHP, as the HTML. When a separation like this occurs, lot of time is spent fixing CSS issues, and going through the CSS sounds like a headache.

Once upon a time, some people created some concepts for the development : Don't Repeat Yourself, Keep It Simple Stupid. Those concepts looks like forgotten when developers create CSS.

Let's see how to bring them back to the scene, let's power the CSS production.

1. Small files, please

First, whatever the context is, when you produce some code : create small and separated files.

For example, separate by purpose, as isolated as possible:

  • reset.css
  • main.css
  • banner.css
  • header.css
  • footer.css
  • etc.

When I search something, I know the file to open, The feature is isolated. The refactoring of a feature would be fast, easy and isolated enough.

2. Sass : it's f#~king awesome

Sass is an extension of CSS adding new features to the language : mixins, variables, inheritance and more.

A Sass file looks like this:

@mixin message-color($color, $bg)
   color:            $color
   border:           1px solid $color
   background-color: $bg

#messages

   .error, .success
       margin:           1em
       padding:          1em

   .error
       @include message-color(red, #ffaaaa)

   .success
       @include message-color(green, #aaffaa)

Sass allows to produce meaningful stylesheet code. Here we see different concepts in Sass. But to be fully impressed by Sass, you should visit the website and see examples.

The main idea is avoid repeating or computing values. Each time you are about to repeat something (a selector, a CSS ruleset), there is a method for it in Sass.

For example, to avoid computing:

$headerHeight: 50px
$menuHeight:   20px

#header
   position: relative
   height:   $headerHeight
#menu
   position: absolute
   top:      $headerHeight - $menuHeight
   right:    0
   height:   $menuHeight

Here you can modify later the $menuHeight or $headerHeight, there is no need to modify 20 different lines, no need to search where the value is used, and no meaningless value in your CSS (height: 42px, what's this value ?).

Another useful command, when you already have existing CSS is sass-convert. This command will convert to CSS to Sass files :

sass-convert my-file.css my-file.sass

This command has no magic inside, and cannot guess computed values, but it's a good start for Sass.

3. Compass, a framework over Sass

Sass provides the language. Compass provides the tools! Compass is a CSS authoring framework. It provides you helpers and utilities like image-width, and sprite-* methods. A reference guide is available with every methods.

A quick-example of features available with it:

@include "compass/reset" // Reset CSS
$logoUrl: "/logo.png"
$bgColor: blue

#header
   color: $bgColor
   background-color: lighten($bgColor, 40%)
#logo
   width:      image-width($logoUrl)
   height:     image-height($logoUrl)
   background: url($logoUrl)
   span
       display: none

Sprite-generation also become very easy with Compass. Here's a small sample of sprite-generation used for the menu of this website:

$menu: sprite-map("sprites/menu-*.png");
#menu
   li
       background-image: sprite-url($menu)
   li.blog
       background-position: sprite-position($menu, "blog")
   li.cv
       background-position: sprite-position($menu, "cv")
   li.contact
       background-position: sprite-position($menu, "contact")

Awesome, heh ?

The sprite-image is generated automatically, so no need to refactor the CSS and the sprite-image when you modify an image.

4. Assetic : the magic key

Kris Wallsmith created an awesome tool for asset management: Assetic. For a brief introduction on "how it works" and "what's in it", please see his presentation on Symfony Live (slides here).

First of all, separate two things: Assetic and AsseticBundle.

Assetic is the library providing the filters, the asset manager, the formula loader, and so on. It comes with many pre-configured filters for Sass, Compass and others. It also provides the tools for combining assets.

AsseticBundle is the integration in Symfony2 providing iteration of templates to find formula, automatic generation of them in development, CLI tools, and so on.

Sample with Symfony2, Sass & Compass

Let's see how to create a Symfony2 project with some Sass files.

First, install Sass & Compass (cf Sass website <http://sass-lang.com/>_ and Compass install guide <http://compass-style.org/install/>_).

Then, enable filters in your application in app/config/config.yml. Here, I indicate to Compass where all my images are located. So when I say url('/images/logo.png'), he knows it means /my/project/web/images/logo.png.

parameters:
  # Assetic
  assetic.filter.compass.images_dir: %kernel.root_dir%/../web/images
  assetic.filter.compass.http_path: /images

assetic:
  debug: %kernel.debug%
  use_controller: false
  filters:
    sass: ~
    compass: ~

Then, create a stylesheets.html.twig containing your assets definition :

{% stylesheets filters="compass"
   "@AlomMainBundle/Resources/assets/css/main.sass"
   "@AlomMainBundle/Resources/assets/css/header.sass"
   "@AlomMainBundle/Resources/assets/css/footer.sass"
%}
   <link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}

And I include it in my layout:

<!- ... -->
<head>
   {% include "::stylesheets.html.twig" %}
</head>

And that's all.

For the development environment, stylesheets are generated automatically. For the production environment, you need to generate assets before, by running :

./app/console assetic:dump --env=prod --no-debug

And that's all.

Conclusion

Mastering CSS is important for a project. Develop them the same way you develop the rest of the application is very important if you want to make the code evolve and want something reusable. This article shows you how to take benefit from modern technologies : Sass, Compass, Assetic, and Symfony2.

Even if you are not using Assetic and Symfony2, Sass & Compass are too awesome to be unused : you can use them for generating HTML templates by using Compass CLI tools.

29 November 2012 - Update

You may have problems when launching assetic command, getting exceptions. If it is so, I recommend you to complete the reading with this excellent article from Luis Cordova.

Paths should not be expressed using @AcmeDemoBundle/Resources/... but should be expressed with bundles/acmedemo/....