A study of Sass (meta-language on top of CSS)
I’ve been experimenting with different technologies as I learn Ruby on Rails and recently I have been looking into using HAML instead of ERB and Sass instead of CSS. I started using HAML a while back and I really enjoy how clean the template files look. This article has an argument for HAML and I agree with the author. I found an article on A List Apart on sprites and I thought it was a good way to showcase the awesomeness of Sass. The article covers creating an image map with a hover effect.
The Links
The HTML for the map is below: (I modified the IDs from the original article to make it simpler to follow)
1 2 3 4 5 6 | <ul id="menu" > <li id="menu_item1"><a href="#1"></a></li> <li id="menu_item2"><a href="#2"></a></li> <li id="menu_item3"><a href="#3"></a></li> <li id="menu_item4"><a href="#4"></a></li> </ul> |
Here is the same map in HAML: (WP-Syntax does not support HAML/Sass, but this is not too bad)
1 2 3 4 5 6 7 8 9 | %ul#menu %li#menu_item1 %a{:href => "#1"} %li#menu_item2 %a{:href => "#2"} %li#menu_item3 %a{:href => "#3"} %li#menu_item4 %a{:href => "#4"} |
The Style
In the article they discuss how the hover effect is achieved using this image. (dimensions added for clarity)

The CSS used for the hover effect is below with some minor modifications to the original:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #menu { width: 400px; height: 200px; background: url(../../images/test-1.jpg); margin: 2em 2em; padding: 0; position: relative; } #menu li, #menu a { height: 200px; display: block; } #menu li { position: absolute; list-style: none; } #menu_item1 {margin-left: 0; width: 96px;} #menu_item2 {margin-left: 96px; width: 76px;} #menu_item3 {margin-left: 172px; width: 111px;} #menu_item4 {margin-left: 283px; width: 118px;} #menu_item1 a:hover { background: transparent url(../../images/test-1.jpg) 0 -200px no-repeat; } #menu_item2 a:hover { background: transparent url(../../images/test-1.jpg) -96px -200px no-repeat; } #menu_item3 a:hover { background: transparent url(../../images/test-1.jpg) -172px -200px no-repeat; } #menu_item4 a:hover { background: transparent url(../../images/test-1.jpg) -283px -200px no-repeat; } |
In the article they discuss the math that must be performed to make this work, but it’s hard to go from all the values presented to the logic that was used to arrive at those values. In addition, there are a lot of constants and repetition in the CSS. Not very DRY in my mind. Now here is the Sass that will produce the same CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | !menu_image = "url(../../images/test-1.jpg)" !width_item_1 = 96 !width_item_2 = 76 !width_item_3 = 111 !width_item_4 = 118 !height_menu = 200 !unit = px #menu :margin 2em 2em :position relative :width 400px :height = !height_menu + !unit :padding 0 :background = !menu_image a :height = !height_menu + !unit :display block li :display block :position absolute :list-style none :height = !height_menu + !unit &#menu_item1 :margin-left 0 :width = !width_item_1 + !unit a:hover :background = "transparent " !menu_image "0 " -(!height_menu) + !unit no-repeat &#menu_item2 :margin-left = !width_item_1 + !unit :width = !width_item_2 + !unit a:hover :background = "transparent " !menu_image " " -(!width_item_1) + !unit " " -(!height_menu) + !unit no-repeat &#menu_item3 :margin-left = (!width_item_1 + !width_item_2) + !unit :width = !width_item_3 + !unit a:hover :background = "transparent " !menu_image " " -(!width_item_1 + !width_item_2) + !unit " " -(!height_menu) + !unit no-repeat &#menu_item4 :margin-left = (!width_item_1 + !width_item_2 + !width_item_3) + !unit :width = !width_item_4 + !unit a:hover :background = "transparent " !menu_image " " -(!width_item_1 + !width_item_2 + !width_item_3) + !unit " " -(!height_menu) + !unit no-repeat |
The top of the Sass file defines the constants that will be used for all the calculations in the CSS. This may seem like a little extra work, but it has a few advantages. First, this makes it simpler to calculate the position of the background image for the :hover and it allows the developer to quickly change the CSS if the image changes. For example, imagine that the image changed to this:

Not only did the dimensions for each item change, but the overall height changed from 200 to 50. If CSS was written directly, not only would the url to the new image need to be changed, but the positions would have to be recalculated and the height and negative y-position would need to change. Using Sass, we can just change the constants defined at the top of the Sass file:
1 2 3 4 5 6 7 | !menu_image = "url(../../images/test-2.png)" !width_item_1 = 75 !width_item_2 = 100 !width_item_3 = 50 !width_item_4 = 175 !height_menu = 50 !unit = px |
I like the simplicity and flexibility that Sass enables when defining CSS. When I learned about CSS, the selling point was to allow the design of a site to be flexible, but having to statically define colors, positions, heights and widths for items like the one discussed here, make maintenance more complex and error prone. Imagine the potential for errors when the image was changed above. Finally, I believe maintenance and readability increases as it is simple to follow how the values are arrived at instead of simply stating the value.
Sass has a lot more to offer than what I present above. If you would like to learn more check out the HAML/Sass site.
No related posts.
Related posts brought to you by Yet Another Related Posts Plugin.
Comments
8 Comments on A study of Sass (meta-language on top of CSS)
-
Chris Eppstein on
Mon, 15th Jun 2009 1:10 PM
-
Enrico on
Mon, 15th Jun 2009 1:19 PM
-
Noel Gomez on
Mon, 15th Jun 2009 1:22 PM
-
Noel Gomez on
Mon, 15th Jun 2009 1:29 PM
-
Thomas Reynolds on
Mon, 15th Jun 2009 1:44 PM
-
Noel Gomez on
Mon, 15th Jun 2009 1:54 PM
-
Noel Gomez on
Mon, 15th Jun 2009 2:11 PM
-
Chris Eppstein on
Mon, 15th Jun 2009 9:35 PM
Great write up. Just a few small comments:
Sass understands units, you don’t need the !unit constant, you can just change all your numbers to be 75px, 100px, etc.
Also, since you’re generating nested selectors, and since they are so tied to the image, I’d recommend using semantic ids for the target of the link — don’t bother with generality (E.g. “menu_item4″) where it detracts from the clarity of what the code is doing without adding value through re-use.
Chris
You could probably go one step further and define a mixin for the menu item styles if you use edge Sass. Parameterized mixins FTW. I also highly recommend Compass. Seriously awesome tool for working with Sass. =)
Thanks Chris. As I mentioned I am still quite new to Sass so I didn’t know you could do that. Point taken on the IDs.
Entico, Yes, I have been playing with Compass as well, really cool.
Here is a reimplementation taking advantage of Sass mixins and unit math:
http://gist.github.com/130367
Note, this requires the “haml-edge” gem as mixins cannot take multiple params in the currently released version of haml.
Thomas,
I tried this but the background image position is not compiled properly. For example,
:background= “transparent” !menu_image !horizontal_indent -!height_menu “no-repeat”
is compiled to
background: transparent url(../../images/test-1.jpg) -200px no-repeat;
!horizontal_indent -!height_menu is compiled into a single value
I got it to work by changing this in the mixin
:background= “transparent” !menu_image “” -!horizontal_indent “” -!height_menu “no-repeat”
the first “” adds a space after the url and the second prevents the values from being summed.
Thomas’s gist works for me without modification. Maybe you need to upgrade sass, Noel. Also that gist is a very nice evolution, thomas.
Also, in a compass project, your image reference should be simplified to:
!menu_image = image_url(“test-1.jpg”)
Tell me what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!










