Tuesday, November 18, 2008

Creating a Reusable Three-column Layout using Compass

Let's pretend we want to build a three column layout like so: Using blueprint, the page is divided into 24 columns. In just a few minutes we whip out our three column layout for our webpage: And here's our stylesheet that implements this layout: Again, this is as easy to use as blueprint, but we've avoided making the mistake of putting presentation in our content. Now let's say you have several different templates and you've been good about making nice semantic names for the different pages and none of the IDs are the same. But we want all of these pages to use the same layout. This is where your power to create abstraction comes in. Using Sass you can define your own mixins that you can reuse! So you start by defining a three column mixin: Now you can now simplify your layout declaration even further:

A Compass Primer

The goal of this post will be to help you install Compass and Sass and then learn the basics. When you are done, if you follow along, you will have a working stand-alone compass project. If you're looking to better understand what Compass can do for you, please read the compass introduction and then come back. If you plan to use Compass with Rails, Merb, or StaticMatic, there's specific installation instructions for each available on the wiki but for now, you can follow along without them.

Some Basic Prerequisites

  • Both Compass and Sass require you to have Ruby installed. If you don't have ruby installed, please do so now.
  • Please make sure you have rubygems version 1.3 or greater by running gem -v.
  • Using compass will require you to do some basic command line work. If you're not comfortable using the command line, you should probably pass on Compass for a while until we get more users and some IDE support, etc.

Installing Compass

$ gem sources --add http://gems.github.com/
$ sudo gem install chriseppstein-compass
You have successfully installed compass if you can perform this command:
$ compass -v
Compass 0.8.15
Copyright (c) 2008 Chris Eppstein
Released under the MIT License.
Sass, which is part of the Haml project, was also installed for you. Sass comes with two command line tools that you should be aware of:
  • sass - A sass compiler for single files and directories that emits css.
  • sass-convert - A sass translator for your existing css, less, sass, and scss files.
Both of these tools also operate on "stdin" for easy integration with other command line tools and GUIs.

Setting up your First Compass Project

We will now create a new project named "my_compass_project" based on blueprint. The contents of the project will be placed into the my_compass_project subdirectory of your current directory -- which will be created for you.
$ compass create my_compass_project --using blueprint --syntax sass
  directory my_compass_project/
  directory my_compass_project/images/
  directory my_compass_project/src/
  directory my_compass_project/src/partials/
  directory my_compass_project/stylesheets/
     create my_compass_project/config.rb
     create my_compass_project/src/screen.sass
     create my_compass_project/src/partials/_base.sass
     create my_compass_project/src/print.sass
     create my_compass_project/src/ie.sass
     create my_compass_project/images/grid.png
     exists my_compass_project/stylesheets
    compile my_compass_project/src/ie.sass
     create my_compass_project/stylesheets/ie.css
    compile my_compass_project/src/print.sass
     create my_compass_project/stylesheets/print.css
    compile my_compass_project/src/screen.sass
     create my_compass_project/stylesheets/screen.css

  *********************************************************************
  Congratulations! Your compass project has been created.

  You may now add and edit sass stylesheets in the src subdirectory of your project.

  Sass files beginning with an underscore are called partials and won't be
  compiled to CSS, but they can be imported into other sass stylesheets.

  You can configure your project by editing the config.rb configuration file.

  You must compile your sass stylesheets into CSS when they change.
  This can be done in one of the following ways:
    1. To compile on demand:
       compass compile [path/to/project]
    2. To monitor your project for changes and automatically recompile:
       compass watch [path/to/project]

  More Resources:
    * Wiki: http://wiki.github.com/chriseppstein/compass
    * Sass: http://sass-lang.com
    * Community: http://groups.google.com/group/compass-users/


  Please see the blueprint website for documentation on how blueprint works:

      http://blueprintcss.org/

  Docs on the compass port of blueprint can be found on the wiki:

      http://wiki.github.com/chriseppstein/compass/blueprint-documentation

  To get started, edit the screen.sass file and read the comments and code there.

  To import your new stylesheets add the following lines of HTML (or equivalent) to your webpage:
  <head>
    <link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/print.css" media="print" rel="stylesheet" type="text/css" />
    <!--[if lt IE 8]>
        <link href="/stylesheets/ie.css" media="screen, projection" rel="stylesheet" type="text/css" />
    <![endif]-->
  </head>

As you can see from the output several new directories have been created, some sass files have been added already and they've even been compiled to css for you. Before we change anything let's verify that our project is working out of the box.

Create an HTML file

Let's create the following html file named index.html in the my_compass_project directory:

Now open index.html in your browser and you should see a nice looking H1 that is left justified within the centered 950px blueprint grid container.

A Quick Intro to Sass

As mentioned already, Compass is built on top of the Sass stylesheet language. Before we can style our webpage, we should review some Sass basics. Sass provides a much cleaner syntax than CSS for styling your webpages. But before we style our ours, let's review some of the basics of the Sass language. First and foremost, Sass allows you to use indentation to indicate a descendent selector, yielding style

Which generates two css rules that look like: This ability to scope selectors allows you to easily avoid the dreaded "CSS Spaghetti" where your styles and class names end up bleeding into areas where you'd rather they didn't. Have you ever wanted to name your colors so that you wouldn't have to remember the hex values or so that you could change them easily? Sass provides variables to which you can assign values and reuse them over and over again: Do you find recurring patterns for styles and copy and pasting them into different selectors? Sass provides a concept called a mixin that addresses this problem. You can define a mixin like so: And once you'd defined your mixin, you can "mix it" into any selector like so: Mixins can also take arguments, define rules for descendants, and even include other mixins: +clearfix is a mixin provided by the compass utilities module that makes sure the bottom of an element containing floated elements falls below the contained elements. These mixins can be used like so:

This ability to create abstractions using mixins is what makes Compass possible and what makes your life easier. Sass has many features that I cannot cover here, I highly encourage you to go read the Sass documentation to learn more.

Introduction to Blueprint

If you are familiar with the Blueprint CSS Framework, you can now use it just as you would have without compass. All of the Blueprint classes are defined and available to you. If you're not familiar with blueprint, I'll give a quick overview here:

Blueprint creates a 950px wide container that is divided into 24 units across. Each unit is composed of 30px of content space and 10px of gutter space. Using the +column mixin you can define an element as a column that is some number of units wide. Columns are floated left and new rows are created by this floating whenever an element would extend past the container bounds. For this reason, we have to tell the last element on a row that it is the last one so that it knows to remove the 10px gutter on the right side and fit into the current row. When a columns is 24 units wide it is implied that it is the last column for the row and so it is safe to omit the last argument from those column declarations. Columns can be nested in which case the nested columns must add up the the width of the containing column and each row of nested columns must end with an additional last option. Please see the wiki for a complete reference of the blueprint grid library.

Getting Semantic

However, the very reason that compass was created was to make it possible for us to avoid using presentational class names in our markup. So let's rip out a few things that we're not going to use to avoid enlarging our stylesheet unnecessarily.

Open up src/screen.sass in your text editor and change it to this:

This change removes the blueprint grid classes from our generated CSS, we don't need them because we're going to use the blueprint library's grid mixins with our semantic markup instead.

Let's briefly go over the changes we've made here:
  • First, we're only applying these styles to pages that have a body class of "blueprint". This is entirely optional, but as a best practice, I encourage you to always scope your styles by a body class or id so they don't appear where you intend them to.
  • We've taken out the generic +blueprint mixin that adds the entire blueprint framework and replaced it with +blueprint-typography which only styles our typography.
  • We've told the class .container that it is a blueprint container on body.bluprint pages.
The parts that didn't change:
  • @import directives make different sass libraries available to us. If those libraries have styles in them, those styles are added to our pages as is the case for the compass/reset.sass which will do a global reset to all pages that include this stylesheet. For more information on css resets, please read Eric Meyer's Post. It is also possible to selectively reset only certain pages, but that is outside the scope of this post.
  • the scaffolding import and the +bluprint-scaffolding call makes our page look nicer as we're first getting started, but soon enough we'll want to pull these out because the styles it provides usually get in the way of a fully styled website.
Now we update our CSS files by running the compass command line while in the my_compass_project directory.

$ compass compile
compile src/ie.sass
overwrite stylesheets/ie.css
compile src/print.sass
overwrite stylesheets/print.css
compile src/screen.sass
overwrite stylesheets/screen.css
Reload index.html and things should look exactly the same.

Setting up auto-updates

We'll be making a number of stylesheet changes going forward and having to run the compass command-line after each edit gets tedious. So compass provides a "watch" mode that will monitor your project for changes and recompile your stylesheets automatically. In your project directory run the following command:

$ compass watch
If you encounter an error, the details will appear at the top of your webpage.

Styling your First Page

Now it's time to add some content to our page and style it. Let's update the container element in our index.html to the following: We will now style this page to have a header, footer, sidebar and primary content area using blueprint grid mixins. Open src/screen.sass in your text editor change it to the following: These sass mixins assign blueprint styles to our page that causes it to be laid out nicely. After saving, the css should have been automatically compiled for you. Go ahead and reload your index.html. It looks pretty good, but I think the header needs a little cleanup so we'll apply some basic styling as well as some compass utilities to it: First, let's pull in the compass utility library by adding an import: @import compass/utilities And then amend the #header style rules like so: You'll notice we've floated the h1 left and the site actions right. I've also told the site-actions list to be a horizontal-list, which is a very handy utility mixin provided by compass. Reload the page, and I hope you'll agree that looks pretty decent. Let's take a look at the css we've generated just for giggles:

Conclusion

Well, you've seen how to style a page using Sass and Compass. We've only just scratched the surface here. I hope this was enough to get you started. From here you should go read the wiki, and ask questions on the mailing list if you get stuck.

See Also

If you found this post confusing (or maybe slightly out of date), there is a very nice blog post here on how to get compass running and it explains some of the basics.

Saturday, November 1, 2008

Introducing Compass.

Pointing the way to cleaner, more maintainable stylesheets.

Are you stuck in a web of CSS Spaghetti? Are you tired of starting from scratch with every website that you build? Don't designers deserve tools to create abstractions just like their programmer buddies? With compass you start with a vocabulary of common styling patterns and best practices all wrapped up and ready to go. With Compass, you don't write CSS! CSS was designed to make browsers efficient, not designers. Instead you write your stylesheets in a language called Sass and it gets converted to CSS for you. But don't let this frighten you. Sass was designed to make CSS easier. So let's start with a really simple example. Ever wanted a list that was displayed horizontally instead of vertically? I thought so. In fact, you probably have a css class tucked away somewhere called "horizontal" that you can apply to lists to achieve this effect. If you do, you've created an abstraction that you can apply to your html to achieve a desired presentation. This is practical and I understand why you've done this but that doesn't change the fact that you're doing it WRONG! You've heard the CSS Experts talk about writing "Semantic" HTML and how you should keep your content and styles separate. But the power of abstraction to simplify your immediate task at hand always trumps the theoretical benefit of "doing it right." Using Compass and Sass, you no longer have to make this trade-off -- Doing the right thing now is just as easy as doing the wrong thing was. So instead of doing this: You can omit the non-semantic "horizontal" class and just add this to your stylesheet instead: +horizontal-list is called a "Mixin". It adds a behavior to the "ol#menu" selector. A mixin can add styles and nested rules. So the above code generates the following CSS: Aren't you glad you didn't have to write all that by hand?

Why does semantic markup matter?

I'll direct you to a page on my website and point out that there's three menus on this page. There's a top menu for general navigation, a context menu on the left side, and a footer menu. Each of them looks completely different and yet the same code was used to generate the html for each one. The only difference is how they are styled. Certainly doable without Compass, but because our abstractions live in the stylesheets, it was no harder than styling custom generated html for each with the corresponding utility class names in the html markup.

We've only scratched the surface.

There are about twenty utility mixins (and growing) found in compass to make the things you do every day as a designer easier. But compass is much more than a collection of utilities. Compass contains a complete port of the Blueprint CSS Framework. And if that's not enough, Compass is designed to work with other CSS frameworks as well and it will even let you mix and match them. For instance, at Caring.com we use YUI's font system and base styles but Blueprint's grid system.

Are you ready to get started?

It's time to read the Compass Primer. You can also head over to the wiki and read the Getting Started page.

Don't forget

Please follow the Compass project on github to stay up to date on developments and join the Mailing list for major announcements and support. For now, please report any bugs you find to the mailing list.

Back after a Hiatus

It's been a year and a half since I joined Caring.com. I've learned a whole hell of a lot during that time and instead of sharing my trials and tribulations of learning rails and building out a pretty darn complex website, I'm going to shift the focus of this blog to share how we're doing things that are different and unique.

Caring.com engineers have produced no fewer than ten unique open source projects as part of our work on the site and have contributed features and bug fixes to numerous open source projects like haml, rails, beanstalk, and git. I'm pretty darn proud of us and I intend to start sharing more about the great things we do.

We've just launched a complete redesign of the site. From a technical perspective, this launch was a resounding success. We have a very solid feature set that exceeded expectations, and we did this with just four engineers. As the architect, I did some up-front coding and planning and got our application infrastructure in place so that the rest of the team could hit the ground running. I spent about two months preparing while the others were building other features. In that time, I overhauled our core data model, implemented dramatic changes to the Cells project, created an entire stylesheet framework built on the awesomeness that is Sass, and eventually ended up joining the HAML project as a core contributor. Needless to say, I've been busy and my family is glad that things are cooling off a bit.

Seven weeks before launch we still didn't have a single template built but I had all the infrastructure in place when the full team finished their other work. Truth be told, I was freaking out and didn't imagine that we would hit our date. But 5 weeks later we were feature complete and two weeks after that we had all the bugs fixed and the site was looking better in all our target browsers than it had ever looked before. The engineers kept complaining that things were too easy and straight-forward and they didn't have to think enough when building out the features. In other words: music to my ears.

In the coming weeks and months, I will be sharing with you as much as I can about how four engineers in five weeks rebuilt what amounted to a complete rewrite of the "core" of caring.com: Our content system. I will also be describing the open source projects Caring.com is contributing back to the open source community that has given so much to us. I hope you find it interesting and at least somewhat helpful.

Thursday, April 17, 2008

Rails partial collection counter behavior changed

In migrating from rails 1.2 to 2.1 (edge), we found that the automatic counter is no longer a zero-based index, it starts with 1 now. I can see how that's a more useful default but it took a while to figure out why all our partial_counter == 0 conditions were failing.