Edit : I no longer use Compass. Just sayin'.
Compass is a CSS authoring framework dedicated to Sass. Not only is it insanely powerful, but it also includes a large range of built-in functions and mixins, easing daily tasks.
It occurred to me there was a couple of Compass features which remain pretty much unknown to most users so I thought it could be a good idea to write a short blog post about them.
Opposite-position()
Compass defines 5 CSS constants: top
, right
, bottom
, left
and center
.
The point of these inalterable variables is to use the opposite-position()
function which returns the opposite value for each constant. Please consider the following example:
$direction: left;
$opposite: opposite-position($direction); /* Outputs “right” */
$position: top right;
$opposite: opposite-position($position); /* Outputs “bottom left” */
Note: the opposite of center
is center
.
I personally used this extension in this very site, when it comes to images and quotes pulling (L32 and L47).
@mixin pull-quote($direction) {
$opposite: opposite-position($direction);
text-align: $opposite;
float: $direction;
margin: 0 0 0.5em 0;
margin-#{$opposite}: 1em;
border-#{$opposite}: 6px solid hotpink;
padding-#{$opposite}: 1em;
}
So $opposite
equals right when $direction
is left and vice versa. Allows me to make only one mixin instead of 2!
Elements-of-type()
Element-of-type() is a built-in function to detect the display type of an element: block
, inline
, inline-block
, table
, table-row-group
, table-header-group
, table-footer-group
, table-row
, table-cell
, list-item
and -as odd as it may look- html5
, html5-inline
and html5-block
.
Note: html5
, html5-inline
and html5-block
are not real display values; they are just keywords to gather all html5 elements (inline, block or both).
This may be useful as part of a CSS reset for example:
@mixin reset-html5 {
#{elements-of-type(html5-block)} {
display: block;
}
}
This snippet forces all HTML5 elements to be displayed as block-elements, even by unsupported browsers.
Experimental()
Experimental has to be one of the most used function in Compass and probably one of the less known at the same time.
Basically, experimental()
allows you to define mixins outputing content depending on enabled vendor prefixes. It is used in all CSS3 built-in mixins. When you use @include box-sizing(border-box)
, here is what happen:
@mixin box-sizing($bs) {
$bs: unquote($bs);
@include experimental(box-sizing, $bs, -moz, -webkit, not -o, not -ms, not -khtml, official);
}
This outputs:
.element {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
-o-
, -ms-
(and -khtml-
) are omitted because the box-sizing()
mixin calls experimental()
by specifically specifying not to output lines for Opera and Internet Explorer.
Now what’s the point of such a tool? As an example, there is no default mixin for CSS animation in Compass. Let’s make one!
@mixin animation($content) {
@include experimental(animation, $content, -webkit, -moz, not -o, not -ms, official);
}
.element {
@include animation(my-animation 3s ease);
}
This outputs:
.element {
-webkit-animation: my-animation 3s ease;
-moz-animation: my-animation 3s ease;
animation: my-animation 3s ease;
}
Hacks
Hum, hacks. I know what you think: NOOOOOO!. Anyway, Compass provides a couple of features to take advantage of Internet Explorer inconsistencies and weaknesses.
You may have already heard of has-layout
. This article explains it way better than I could:
“Layout” is an IE/Win proprietary concept that determines how elements draw and bound their content, interact with and relate to other elements, and react on and transmit application/user events. This quality can be irreversibly triggered by some CSS properties. Some HTML elements have “layout” by default. Microsoft developers decided that elements should be able to acquire a “property” (in an object-oriented programming sense) they referred to as hasLayout, which is set to true when this rendering concept takes effect.
Back to our business: Compass gives two ways to trigger hasLayout
on elements: with zoom
(using the zoom
MS proprietary property) or with block
(using the display
property). I’d go with the zoom, even if it doesn’t validate mostly because I’m used to.
.element1 {
@include has-layout(zoom);
}
.element2 {
@include has-layout(block);
}
Outputs…
.element1 {
*zoom: 1;
}
.element2 {
display: inline-block;
}
.element2 {
display: block;
}
You now understand why I use the zoom approach. Otherwise, Compass also provides another way to target IE6 specifically called the bang hack. It relies on the inability for IE6 to understand the !important
flag:
.element1 {
@include bang-hack(color, red, blue);
}
Outputs…
.element1 {
color: red !important;
color: blue;
}
Since IE6 doesn’t understand !important
, it will apply the later declaratation while other browsers will follow the hammer bash flaged rule.
Image dimensions
Compass gives you a way to know the dimensions of an image (given as a path) with 2 functions: image-width()
and image-height()
.
.element {
$image: 'my-awesome-background.jpg';
background: url($image);
width: image-width($image);
height: image-height($image);
}
In this example, the element will have a size relative to the background-image it uses.
Note: beware, the path has to be relative to your project’s image directory, defined in your config.rb
file.
Math functions
If you’re like a total nerd and want to do CSS with math, then you’ll be pleased to know Compass has a bunch of built-in math functions like sin()
, cos()
, pi()
among a few others.
I once had to use sin()
in order to make a mixin for a pure CSS 6-points star but that’s pretty much it. If you happen to have a real live use case for one of those functions, I’d be more than pleased to know more about it.
$n: 4;
$pow: pow($n); /* Returns 16 */
$sqrt: sqrt($n); /* Returns 2 */
Selector helpers
Compass provides some features to play with selectors like nest()
, append-selector()
or headings()
.
Once again, I am not sure if there are a bunch of real life use cases for such functions. Let me show you with a demo, maybe you’ll be able to find a use case:
/* nest() */
nest(".class1", ".class2");
/* Outputs ".class1.class2" */
nest(".class1, .class2", ".class3");
/* Outputs ".class1.class3 .class2.class3" */
/* append-selector */
append-selector(".class1", ".class2");
/* Outputs ".class1.class2" */
append-selector("a, p, li", ".class");
/* Outputs `a.class, p.class, li.class` */
/* headings() */
#{headings()} {
font-family: 'My Awesome Font';
/* Set font-family to all headings */
}
#{headings(1, 3)} {
font-weight: bold;
/* Set font-weight to h1, h2, h3 */
}
Image-replacement functions
Compass provides several resources to ease a daily task: image replacement. When you have an element with text content, but you want the text to disappear to see the background image instead.
.element {
@include hide-text(right);
}
Outputs…
.element {
text-indent: 110%;
white-space: nowrap;
overflow: hidden;
}
The hide-text()
mixin takes a direction as a parameter. The default one is left
, resulting in a text-indent: -199988px
with a 16px
baseline. You definitely should use right
for better performance.
Final words
So people, how many of these features did you know? If you have some free time, I highly recommand you to dig into Compass documentation. You’d be surprised how little you know about the framework in most cases.