Find file
Fetching contributors…
Cannot retrieve contributors at this time
392 lines (279 sloc) 10.7 KB

Using Chance

This guide covers using Chance, SproutCore’s CSS framework. You’ll
learn to:

  • Use SCSS syntax to reduce code and keep it clean.
  • Use $theme to simplify rules.
  • Use the @include slice directive to include images.
  • Use the @include slices directive for multi-slice scaling.


What Is Chance?

Chance is SproutCore’s CSS preprocessor. All CSS in your app goes through Chance.

In addition to having its own CSS extensions, Chance includes SCSS.
Even with all of these extensions, Chance is a superset of CSS. This means that
all normal CSS will still “just work.”

WARNING: Chance expects to work with a SproutCore theme. Recent releases of the SproutCore build tools will set everything up for you, but if your app doesn’t have a theme.js file, you need to follow the directions in Theming Your App: Giving Your App a Theme


As much as we’d like to take credit for SCSS, we cannot: it does not stand
for “SproutCore Stylesheets.” It actually stands for “Sassy CSS” because it
is part of “Sass:” Syntactically Awesome Stylesheets.

NOTE: Although Sass’s own build tool only sends files with the extension .scss through the SCSS processor, SproutCore sends all CSS, including .css files, through SCSS. Give your files the .css extension.

SCSS has many features. We’ll cover the ones most useful for theming SproutCore.
For full reference, refer to the official SCSS documentation.


You know those dolls that fit one inside the other? Nesting looks a little like that:

.yo-dawg {
color: blue;

.i-put-a-rule-in-your-rule { color: red; .so-you-can-style-while-you-style { color: green; } }


But what does it mean? Well, CSS should roughly map to HTML. So, what might some “nested” HTML look like?

<div class = ‘yo-dawg’>
<div class = ‘i-put-a-rule-in-your-rule’>
<span class = ‘im-not-typing-that-long-class——ohwait’>

Aside from the class-that-shall-not-be-typed, the above HTML is what our example
CSS is meant to match. The nesting gets converted:

.you-dawg {
color: blue;

.yo-dawg .i-put-a-rule-in-your-rule {
color: red;

.yo-dawg .i-put-a-rule-in-your-rule .you-know-what {
color: green;

Nesting helps you reduce repetition of class names. The nesting in your CSS matches
your nesting of HTML elements: if rule B is inside rule A, it will match descendants
of elements that match rule A.


Nesting is nice to match elements inside of each other, but what about when you
want to use nesting to match a single element?

For instance, a SproutCore button has normal, active, selected, and active
selected states. The normal state doesn’t have a class name; the others have
class names active, sel, and active sel.

Without nesting, this looks like:

$theme.button {


$ {


$theme.button.sel {


$ {


But nesting won’t work: We can’t nest active inside button because it needs to
match the same element!

SCSS provides &. which does exactly what we want, continuing
the parent selector:


&.active { … } &.sel { … &.active { … } }



You can define variables:

$width: 5px;

.my-thingy {
width: $width;

If you want to share your variable between files, you have to make sure they are loaded
in the right order. The sc_require() function does this:

$width: 5px;

// call sc_require to make sure file1 loads first:

.my-thingy {
width: $width;

$theme Variable

Chance has a special variable: $theme. It contains your theme’s
class names. Using $theme, you can write just $theme.button { … } to style
a button.

$theme gets its initial value from the :css_theme property in your app’s Buildfile:

config :my_app, … :css_theme => “”

@theme Directive

Let’s say you created MyAwesomeTheme. But you need a red variation for all of your
app’s error windows, error toolbars, etc. Creating a brand new theme
doesn’t make sense: it will still be MyAwesomeTheme, just a version for errors.

As described in Theming Your App, you’ll make a child theme:

MyAwesomeTheme.Error = MyAwesomeTheme.subtheme(‘error’);

Now, any time one of your windows, toolbars, or controls sets themeName to error:

MyErrorWindow ={
themeName: ‘error’,


It and all of its children will automatically use your MyAwesomeTheme.Error theme,
and will get class names like ace my-awesome-theme error.

MyAwesomeTheme.Error is nested inside MyAwesomeTheme. Just like how
SCSS’s nesting matches DOM structure, Chance has a tool to match this SproutCore
theme structure:

$theme.button { /* normal styles here */ }

@theme(error) {
$theme.button { /* error styles here */ }

The @theme(theme name) directive adds the theme name provided to the current
theme names stored in $theme. All rules inside the { and } will be part
of your subtheme.

@include slice()

The @include slice() directive lets you include an image in your CSS. You can
include the whole image, or select a portion to extract.
Chance will handle details like spriting or embedding as data: urls.

To include an image, just pass the image name:

.my-image {
@include slice(“my-image.png”);

NOTE: The @include slice() directive works just like the CSS url() directive – linking to images is relative to where your CSS file is located. For instance, if your CSS file is located at apps/your_app/resources/stylesheets/your_app.css and your image is apps/your_app/resources/images/my_image.png, your URL string would be “../images/my_image.png”.

That puts the image as the background. It doesn’t do any “slicing,” however.
Where does the name come from?


Slicing in Photoshop can be annoying and difficult.

Chance lets you slice your images directly in your CSS. To include a
section of the image rather than the whole thing, pass arguments
identifying a rectangle:

.my-image {
@include slice(“my-image.png”, $left: 3, $width: 3);

You don’t have to specify all parameters. For instance, if you only specify
a left, the rectangle will go from there to the right edge. If you only
specify a right, it will go from there to the left edge.

The possible rectangle arguments are: $left, $top, $right, $bottom, $width, $height.


Rather than using background-repeat for slices, you should use the $repeat argument:

.my-image {
@include slice(“my-image.png”, $left: 3, $width: 1, $repeat: repeat-x);

This lets Chance know that the image repeats, which can impact how it deals with the image.
For instance, if Chance were to sprite the image, it would create separate sprites
for each repeat-x, repeat-y, and repeat-both.


@include slice and the background-position property are incompatible. If you need
to offset the position of a background image, you must use Chance’s $offset argument.

$offset takes two numbers: an x offset and a y offset. For example:

.my-image {
@include slice(“my-image.png”, $width: 3, $offset: -1 0);

This will move the background to the left by 1px.

@include slices()

The plural of slice is slices; as such, where @include slice includes a
slice as a background image, you might expect @include slices to include
multiple slices as background images.

You would be correct. @include slices automatically generates CSS for
multi-slice scalable backgrounds.

Controls that support multi-sliced backgrounds all generate some HTML to support it.
The HTML they generate follows a standard form that @include slices matches.

For instance, the controls may write:

<div class = ’left’>
<div class = ’middle’>
<div class = ’right’>

If you use @include slices like this:

$theme.button {
@include slices(“button.png”, $left: 3, $right: 3);

The generated CSS may look like this: .left {
background: …
} .middle {
background: …;
background-repeat: repeat-x;
} .right {
background: …;


You pass the “middle rectangle” to @include slices. It will make slices at
each side, generating up to nine slices: top-left, top, top-right,
left, middle, right, bottom-left, bottom, bottom-right
. Only slices that
actually have content will be generated.

For instance, the above example defines the following rectangle:

You may only use four arguments to specify the rectangle:
$left, $top, $right, and $bottom.

Unlike @include slice(), $width and
$height are not valid.


In a button, the repeat-x segment usually only needs to be one pixel wide. But
if you specify the middle rectangle as in the diagram above, it would repeat
a much wider section! This would be very inefficient.

Because the repeat-x slices usually just need to repeat one pixel horizontally,
Chance will by default only take one pixel. The setting that controls this behavior
is called $fill.

The default $fill is 1 0, which tells chance to grab only one pixel horizontally,
but all the vertical pixels. If you wanted all the horizontal pixels as well, you
could set $fill: 0 0. If you wanted to repeat a 15-pixel segment
horizontally, you would specify $fill: 15 0:

$theme.button {
@include slices(“button-capsule”, $left: 3, $right: 3, $fill: 15 0);


Sometimes you don’t want to include all slices. For instance, let’s say you
want to theme a capsule-style button. You only need to override the images for
the left and right sides: the design for the middle is unchanged.

To avoid needlessly including the same data twice, skip the middle slice:

@theme(capsule) {
$theme.button {
@include slices(“button-capsule”, $left: 3, $right: 3, $skip: middle);

You can supply a space-separated list of slices to skip. The possible slice
names are top-left, top, top-right, left, middle, right,
bottom-left, bottom, and bottom-right.