Sass Changelog

3.3.10 (11 July 2014)

3.3.9 (27 June 2014)

3.3.8 (20 May 2014)

3.3.7 (2 May 2014)

3.3.6 (25 April 2014)

3.3.5 (14 April 2014)

3.3.4 (21 March 2014)

3.3.3 (14 March 2014)

3.3.2 (11 March 2014)

3.3.1 (10 March 2014)

This release includes a number of fixes for issues that popped up in the immediate aftermath of the 3.3.0 release.

Re-bundle listen

With 3.3.0, we un-bundled the listen library from Sass. We did so hoping that it would make it easier for users to keep up to date with the latest features and bug fixes, but unfortunately listen 2.0 and on have dropped support for Ruby 1.8.7, which Sass continues to support. Further complicating things, RubyGems lacks the ability to install only the version of listen supported by the current Ruby installation, so we were unable to use a standard Gem dependency on listen.

To work around this, we tried to piggyback on RubyGems’ native extension support to install the correct version of listen when Sass was installed. This is what we released in 3.3.0. However, this caused numerous problems in practice, especially for users on Windows. It quickly became clear that this wasn’t a viable long-term solution.

As such, we’re going back to the bundling strategy. While not perfect, this worked well enough for the duration of the Sass 3.2 release, and we expect it to cause much less havoc than un-bundling. We’ll bundle listen 1.3.1, the most recent version that retains Ruby 1.8.7 compatibility. If a user of Sass has a more recent version of listen installed, that will be preferred to the bundled version. Listen versions through 2.7.0 have been tested, and we expect the code to work without modification on versions up to 3.0.0, assuming no major API changes.

Smaller Changes

3.3.0 (7 March 2014)

SassScript Maps

SassScript has a new data type: maps. These are associations from SassScript values (often strings, but potentially any value) to other SassScript values. They look like this:

$map: (key1: value1, key2: value2, key3: value3);

Unlike lists, maps must always be surrounded by parentheses. () is now an empty map in addition to an empty list.

Maps will allow users to collect values into named groups and access those groups dynamically. For example, you could use them to manage themes for your stylesheet:

$themes: (
  mist: (
    header: #DCFAC0,
    text:   #00968B,
    border: #85C79C
  ),
  spring: (
    header: #F4FAC7,
    text:   #C2454E,
    border: #FFB158
  ),
  // ...
);

@mixin themed-header($theme-name) {
  h1 {
    color: map-get(map-get($themes, $theme-name), header);
  }
}

There are a variety of functions for working with maps:

All the existing list functions also work on maps, treating them as lists of pairs. For example, nth((foo: 1, bar: 2), 1) returns foo 1. Maps can also be used with @each, using the new multiple assignment feature (see below):

@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
  #{$header} {
    font-size: $size;
  }
}

Produces:

h1 {
  font-size: 2em;
}

h2 {
  font-size: 1.5em;
}

h3 {
  font-size: 1.2em;
}

Variable Keyword Arguments

Maps can be passed as variable arguments, just like lists. For example, if $map is (alpha: -10%, "blue": 30%), you can write scale-color($color, $map...) and it will do the same thing as scale-color($color, $alpha: -10%, $blue: 30%). To pass a variable argument list and map at the same time, just do the list first, then the map, as in fn($list..., $map...).

You can also access the keywords passed to a function that accepts a variable argument list using the new keywords($args) function. For example:

@function create-map($args...) {
  @return keywords($args);
}

create-map($foo: 10, $bar: 11); // returns (foo: 10, bar: 11)

Lists of Pairs as Maps

The new map functions work on lists of pairs as well, for the time being. This feature exists to help libraries that previously used lists of pairs to simulate maps. These libraries can now use map functions internally without introducing backwards-incompatibility. For example:

$themes: (
  mist (
    header #DCFAC0,
    text   #00968B,
    border #85C79C
  ),
  spring (
    header #F4FAC7,
    text   #C2454E,
    border #FFB158
  ),
  // ...
);

@mixin themed-header($theme-name) {
  h1 {
    color: map-get(map-get($themes, $theme-name), header);
  }
}

Since it’s just a migration feature, using lists of pairs in place of maps is already deprecated. Library authors should encourage their users to use actual maps instead.

Source Maps

Sass now has the ability to generate standard JSON source maps of a format that will soon be supported in most major browsers. These source maps tell the browser how to find the Sass styles that caused each CSS style to be generated. They’re much more fine-grained than the old Sass-specific debug info that was generated; rather than providing the source location of entire CSS rules at a time, source maps provide the source location of each individual selector and property.

Source maps can be generated by passing the --sourcemap flag to the sass executable, by passing the :sourcemap option to Sass::Plugin, or by using the Sass::Engine#render_with_sourcemap method. By default, Sass assumes that the source stylesheets will be made available on whatever server you’re using, and that their relative location will be the same as it is on the local filesystem. If this isn’t the case, you’ll need to make a custom class that extends Sass::Importers::Base or Sass::Importers::Filesystem and overrides #public_url.

Thanks to Alexander Pavlov for implementing this.

@at-root

Sass 3.3 adds the @at-root directive, which is a way to tell Sass to put a collection of rules at the top-level root of the document. The easiest way to use it is with a selector:

.badge {
  @at-root .info { ... }
  @at-root .header { ... }
}

In addition to using @at-root on a single selector, you can also use it on a whole block of them. For example:

.badge {
  @at-root {
    .info { ... }
    .header { ... }
  }
}

Also produces:

.info { ... }
.header { ... }

@at-root (without: ...) and @at-root (with: ...)

By default, @at-root just excludes selectors. However, it’s also possible to use @at-root to move outside of nested directives such as @media as well. For example:

@media print {
  .page {
    width: 8in;
    @at-root (without: media) {
      color: red;
    }
  }
}

produces:

@media print {
  .page {
    width: 8in;
  }
}
.page {
  color: red;
}

You can use @at-root (without: ...) to move outside of any directive. You can also do it with multiple directives separated by a space: @at-root (without: media supports) moves outside of both @media and @supports queries.

There are two special values you can pass to @at-root. “rule” refers to normal CSS rules; @at-root (without: rule) is the same as @at-root with no query. @at-root (without: all) means that the styles should be moved outside of all directives and CSS rules.

If you want to specify which directives or rules to include, rather than listing which ones should be excluded, you can use with instead of without. For example, @at-root (with: rule) will move outside of all directives, but will preserve any CSS rules.

Smaller Improvements

Backwards Incompatibilities – Must Read!

3.2.16 (17 March 2014)

3.2.15 (7 March 2014)

3.2.14 (24 January 2014)

3.2.13 (19 December 2013)

3.2.12 (4 October 2013)

3.2.11 (27 September 2013)

3.2.10 (26 July 2013)

3.2.9 (10 May 2013)

3.2.8 (22 April 2013)

3.2.7 (8 March 2013)

3.2.6 (22 February 2013)

3.2.5 (4 January 2013)

3.2.4 (21 December 2012)

3.2.3 (9 November 2012)

3.2.2 (2 November 2012)

Deprecations – Must Read!

3.2.1 (15 August 2012)

3.2.0 (10 August 2012)

@content

A mixin include can now accept a block of content (Reference Documentation). The style block will be passed to the mixin and can be placed at the point @content is used. E.g.:

@mixin iphone {
  @media only screen and (max-width: 480px) {
    @content;
  }
}

@include iphone {
  body { color: red }
}

Or in .sass syntax:

=iphone
  @media only screen and (max-width: 480px)
    @content

+iphone
  body
    color: red

Produces:

@media only screen and (max-width: 480px) {
  body { color: red }
}

Note that the contents passed to the mixin are evaluated in the scope they are used, not the scope of the mixin. More on variable scoping.

Placeholder Selectors: %foo

Sass supports a new, special type of selector called a “placeholder selector”. These look like class and id selectors, except the # or . is replaced by %. They’re meant to be used with the @extend directive, when you want to write styles to be extended but you don’t want the base styles to appear in the CSS.

On its own, a placeholder selector just causes a ruleset not to be rendered. For example:

// This ruleset won't be rendered on its own.
#context a%extreme {
  color: blue;
  font-weight: bold;
  font-size: 2em;
}

However, placeholder selectors can be extended, just like classes and ids. The extended selectors will be generated, but the base placeholder selector will not. For example:

.notice { @extend %extreme; }

Is compiled to:

#context a.notice {
  color: blue;
  font-weight: bold;
  font-size: 2em;
}

Variable Arguments

Mixins and functions now both support variable arguments. When defining a mixin or function, you can add ... after the final argument to have it accept an unbounded number of arguments and package them into a list. When calling a mixin or function, you can add ... to expand the final argument (if it’s a list) so that each value is passed as a separate argument. For example:

@mixin box-shadow($shadows...) {
  // $shadows is a list of all arguments passed to box-shadow
  -moz-box-shadow: $shadows;
  -webkit-box-shadow: $shadows;
  box-shadow: $shadows;      
}

// This is the same as "@include spacing(1, 2, 3);"
$values: 1, 2, 3;
@include spacing($values...);

Finally, if a variable argument list is passed directly on to another mixin or function, it will also pass along any keyword arguments. This means that you can wrap a pre-existing mixin or function and add new functionality without changing the call signature.

Directive Interpolation

#{} interpolation is now allowed in all plain CSS directives (such as @font-face, @keyframes, and of course @media).

In addition, @media gets some special treatment. In addition to allowing #{} interpolation, expressions may be used directly in media feature queries. This means that you can write e.g.:

$media: screen;
$feature: -webkit-min-device-pixel-ratio;
$value: 1.5;

@media #{$media} and ($feature: $value) {
  ...
}

This is intended to allow authors to easily write mixins that make use of @media and other directives dynamically.

Smaller Improvements

Backwards Incompatibilities – Must Read!

@extend Warnings

Any @extend that doesn’t match any selectors in the document will now print a warning. These warnings will become errors in future versions of Sass. This will help protect against typos and make it clearer why broken styles aren’t working. For example:

h1.notice {color: red}
a.important {@extend .notice}

This will print a warning, since the only use of .notice can’t be merged with a.

You can declare that you don’t want warnings for a specific @extend by using the !optional flag. For example:

h1.notice {color: red}
a.important {@extend .notice !optional}

This will not print a warning.

Smaller Incompatibilities

3.1.21 (10 August 2012)

3.1.20

3.1.19

3.1.18

Deprecations – Must Read!

3.1.17

3.1.16

3.1.15

3.1.14

3.1.13

3.1.12

3.1.11

Deprecations – Must Read!

3.1.10

3.1.9

3.1.8

3.1.7

3.1.6

3.1.5

3.1.4

3.1.3

3.1.2

3.1.1

3.1.0

Sass-based Functions

While it has always been possible to add functions to Sass with Ruby, this release adds the ability to define new functions within Sass files directly. For example:

$grid-width: 40px;
$gutter-width: 10px;

@function grid-width($n) {
  @return $n * $grid-width + ($n - 1) * $gutter-width;
}

#sidebar { width: grid-width(5); }

Becomes:

#sidebar {
  width: 240px; }

Keyword Arguments

Both mixins and Sass functions now support the ability to pass in keyword arguments. For example, with mixins:

@mixin border-radius($value, $moz: true, $webkit: true, $css3: true) {
  @if $moz { -moz-border-radius: $value }
  @if $webkit { -webkit-border-radius: $value }
  @if $css3 { border-radius: $value }
}

@include border-radius(10px, $webkit: false);

And with functions:

p {
  color: hsl($hue: 180, $saturation: 78%, $lightness: 57%);
}

Keyword arguments are of the form $name: value and come after normal arguments. They can be used for either optional or required arguments. For mixins, the names are the same as the argument names for the mixins. For functions, the names are defined along with the functions. The argument names for the built-in functions are listed in the function documentation.

Sass functions defined in Ruby can use the Sass::Script::Functions.declare method to declare the names of the arguments they take.

New Keyword Functions

The new keyword argument functionality enables new Sass color functions that use keywords to encompass a large amount of functionality in one function.

Each keyword function accepts $hue, $saturation, $value, $red, $green, $blue, and $alpha keywords, with the exception of scale-color() which doesn’t accept $hue. These keywords modify the respective properties of the given color.

Each keyword function can modify multiple properties at once. For example, adjust-color($color, $lightness: 15%, $saturation: -10%) both lightens and desaturates $color. HSL properties cannot be modified at the same time as RGB properties, though.

Lists

Lists are now a first-class data type in Sass, alongside strings, numbers, colors, and booleans. They can be assigned to variables, passed to mixins, and used in CSS declarations. Just like the other data types (except booleans), Sass lists look just like their CSS counterparts. They can be separated either by spaces (e.g. 1px 2px 0 10px) or by commas (e.g. Helvetica, Arial, sans-serif). In addition, individual values count as single-item lists.

Lists won’t behave any differently in Sass 3.1 than they did in 3.0. However, you can now do more with them using the new list functions:

For more details about lists see the reference.

@each

There’s also a new directive that makes use of lists. The @each directive assigns a variable to each item in a list in turn, like @for does for numbers. This is useful for writing a bunch of similar styles without having to go to the trouble of creating a mixin. For example:

@each $animal in puma, sea-slug, egret, salamander {
  .#{$animal}-icon {
    background-image: url('/images/#{$animal}.png');
  }
}

is compiled to:

.puma-icon {
  background-image: url('/images/puma.png'); }
.sea-slug-icon {
  background-image: url('/images/sea-slug.png'); }
.egret-icon {
  background-image: url('/images/egret.png'); }
.salamander-icon {
  background-image: url('/images/salamander.png'); }

@media Bubbling

Modern stylesheets often use @media rules to target styles at certain sorts of devices, screen resolutions, or even orientations. They’re also useful for print and aural styling. Unfortunately, it’s annoying and repetitive to break the flow of a stylesheet and add a @media rule containing selectors you’ve already written just to tweak the style a little.

Thus, Sass 3.1 now allows you to nest @media rules within selectors. It will automatically bubble them up to the top level, putting all the selectors on the way inside the rule. For example:

.sidebar {
  width: 300px;
  @media screen and (orientation: landscape) {
    width: 500px;
  }
}

is compiled to:

.sidebar {
  width: 300px;
}
@media screen and (orientation: landscape) {
  .sidebar {
    width: 500px;
  }
}

You can also nest @media directives within one another. The queries will then be combined using the and operator. For example:

@media screen {
  .sidebar {
    @media (orientation: landscape) {
      width: 500px;
    }
  }
}

is compiled to:

@media screen and (orientation: landscape) {
  .sidebar {
    width: 500px;
  }
}

Nested @import

The @import statement can now be nested within other structures such as CSS rules and @media rules. For example:

@media print {
  @import "print";
}

This imports print.scss and places all rules so imported within the @media print block. This makes it easier to create stylesheets for specific media or sections of the document and distributing those stylesheets across multiple files.

Backwards Incompatibilities – Must Read!

Sass Internals

3.0.26 (Unreleased)

3.0.25

Tagged on GitHub.

3.0.24

Tagged on GitHub.

3.0.23

Tagged on GitHub.

@charset Change

The behavior of @charset has changed in version 3.0.23 in order to work around a bug in Safari, where @charset declarations placed anywhere other than the beginning of the document cause some CSS rules to be ignored. This change also makes @charsets in imported files behave in a more useful way.

Ruby 1.9

When using Ruby 1.9, which keeps track of the character encoding of the Sass document internally, @charset directive in the Sass stylesheet and any stylesheets it imports are no longer directly output to the generated CSS. They’re still used for determining the encoding of the input and output stylesheets, but they aren’t rendered in the same way other directives are.

Instead, Sass adds a single @charset directive at the beginning of the output stylesheet if necessary, whether or not the input stylesheet had a @charset directive. It will add this directive if and only if the output stylesheet contains non-ASCII characters. By default, the declared charset will be UTF-8, but if the Sass stylesheet declares a different charset then that will be used instead if possible.

One important consequence of this scheme is that it’s possible for a Sass file to import partials with different encodings (e.g. one encoded as UTF-8 and one as IBM866). The output will then be UTF-8, unless the importing stylesheet declares a different charset.

Ruby 1.8

Ruby 1.8 doesn’t have good support for encodings, so it uses a simpler but less accurate scheme for figuring out what @charset declaration to use for the output stylesheet. It just takes the first @charset declaration to appear in the stylesheet or any of its imports and moves it to the beginning of the document. This means that under Ruby 1.8 it’s not safe to import files with different encodings.

3.0.22

Tagged on GitHub.

3.0.21

Tagged on GitHub.

3.0.20

Tagged on GitHub.

3.0.19

Tagged on GitHub.

3.0.18

Tagged on GitHub.

3.0.17

Tagged on GitHub.

3.0.16

Tagged on GitHub.

3.0.15

Tagged on GitHub.

3.0.14

Tagged on GitHub.

3.0.13

Tagged on GitHub.

CSS @import Directives

Sass is now more intelligent about when to compile @import directives to plain CSS. Any of the following conditions will cause a literal CSS @import:

The former two conditions always worked, but the latter two are new.

-moz-calc Support

The new -moz-calc() function in Firefox 4 will now be properly parsed by Sass. calc() was already supported, but because the parsing rules are different than for normal CSS functions, this had to be expanded to include -moz-calc.

In anticipation of wider browser support, in fact, any function named -*-calc (such as -webkit-calc or -ms-calc) will be parsed the same as the calc function.

:-moz-any Support

The :-moz-any pseudoclass selector is now parsed by Sass.

--require Flag

The Sass command-line executable can now require Ruby files using the --require flag (or -r for short).

Rails Support

Make sure the default Rails options take precedence over the default non-Rails options. This makes ./script/server --daemon work again.

Rails 3 Support

Support for Rails 3 versions prior to beta 4 has been removed. Upgrade to Rails 3.0.0.beta4 if you haven’t already.

3.0.12

Tagged on GitHub.

Rails 3 Support

Apparently the last version broke in new and exciting ways under Rails 3, due to the inconsistent load order caused by certain combinations of gems. 3.0.12 hacks around that inconsistency, and should be fully Rails 3-compatible.

Deprecated: Rails 3 Beta 3

Haml’s support for Rails 3.0.0.beta.3 has been deprecated. Haml 3.0.13 will only support 3.0.0.beta.4.

3.0.11

Tagged on GitHub.

There were no changes made to Haml between versions 3.0.10 and 3.0.11.

Rails 3 Support

Make sure Sass actually regenerates stylesheets under Rails 3. The fix in 3.0.10 didn’t work because the Rack stack we were modifying wasn’t reloaded at the proper time.

Bug Fixes

3.0.10

Tagged on GitHub.

Appengine-JRuby Support

The way we determine the location of the Haml installation no longer breaks the version of JRuby used by appengine-jruby.

Rails 3 Support

Sass will regenerate stylesheets under Rails 3 even when no controllers are being accessed.

Other Improvements

3.0.9

Tagged on GitHub.

There were no changes made to Sass between versions 3.0.8 and 3.0.9. A bug in Gemcutter caused the gem to be uploaded improperly.

3.0.8

Tagged on GitHub.

3.0.7

Tagged on GitHub.

Encoding Support

Sass 3.0.7 adds support for @charset for declaring the encoding of a stylesheet. For details see the reference.

The sass and sass-convert executables also now take an -E option for specifying the encoding of Sass/SCSS/CSS files.

Bug Fixes

3.0.6

Tagged on GitHub.

There were no changes made to Sass between versions 3.0.5 and 3.0.6.

3.0.5

Tagged on GitHub.

#{} Interpolation in Properties

Previously, using #{} in some places in properties would cause a syntax error. Now it can be used just about anywhere.

Note that when #{} is used near operators like /, those operators are treated as plain CSS rather than math operators. For example:

p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}

is compiled to:

p {
  font: 12px/30px;
}

This is useful, since normally a slash with variables is treated as division.

Recursive Mixins

Mixins that include themselves will now print much more informative error messages. For example:

@mixin foo {@include bar}
@mixin bar {@include foo}
@include foo

will print:

An @include loop has been found:
    foo includes bar
    bar includes foo

Although it was previously possible to use recursive mixins without causing infinite looping, this is now disallowed, since there’s no good reason to do it.

Rails 3 Support

Fix Sass configuration under Rails 3. Thanks Dan Cheail.

sass --no-cache

Make the --no-cache flag properly forbid Sass from writing .sass-cache files.

3.0.4

Tagged on GitHub.

3.0.3

Tagged on GitHub.

Rails 3 Support

Make sure Sass is loaded properly when using Rails 3 along with non-Rails-3-compatible plugins like some versions of will_paginate.

Also, In order to make some Rails loading errors like the above easier to debug, Sass will now raise an error if Rails.root is nil when Sass is loading. Previously, this would just cause the paths to be mis-set.

Merb Support

Merb, including 1.1.0 as well as earlier versions, should really work with this release.

Bug Fixes

3.0.2

Tagged on GitHub.

Merb 1.1.0 Support

Fixed a bug inserting the Sass plugin into the Merb 1.1.0 Rack application.

Bug Fixes

3.0.1

Tagged on GitHub.

Installation in Rails

haml --rails is no longer necessary for installing Sass in Rails. Now all you need to do is add gem "haml" to the Gemfile for Rails 3, or add config.gem "haml" to config/environment.rb for previous versions.

haml --rails will still work, but it has been deprecated and will print an error message. It will not work in the next version of Sass.

Rails 3 Beta Integration

:template_location Methods

The :template_location option can be either a String, a Hash, or an Array. This makes it difficult to modify or use with confidence. Thus, three new methods have been added for handling it:

3.0.0

Tagged on GitHub.

Deprecations – Must Read!

SCSS (Sassy CSS)

Sass 3 introduces a new syntax known as SCSS which is fully compatible with the syntax of CSS3, while still supporting the full power of Sass. This means that every valid CSS3 stylesheet is a valid SCSS file with the same meaning. In addition, SCSS understands most CSS hacks and vendor-specific syntax, such as IE’s old filter syntax.

SCSS files use the .scss extension. They can import .sass files, and vice-versa. Their syntax is fully described in the Sass reference; if you’re already familiar with Sass, though, you may prefer the intro to SCSS for Sass users.

Since SCSS is a much more approachable syntax for those new to Sass, it will be used as the default syntax for the reference, as well as for most other Sass documentation. The indented syntax will continue to be fully supported, however.

Sass files can be converted to SCSS using the new sass-convert command-line tool. For example:

# Convert a Sass file to SCSS
$ sass-convert style.sass style.scss

Note that if you’re converting a Sass file written for Sass 2, you should use the --from sass2 flag. For example:

# Convert a Sass file to SCSS
$ sass-convert --from sass2 style.sass style.scss

# Convert all Sass files to SCSS
$ sass-convert --recursive --in-place --from sass2 --to scss stylesheets/

Syntax Changes

SassScript Context

The = character is no longer required for properties that use SassScript (that is, variables and operations). All properties now use SassScript automatically; this means that : should be used instead. Variables should also be set with :. For example, what used to be

// Indented syntax
.page
  color = 5px + 9px

should now be

// Indented syntax
.page
  color: 5px + 9px

This means that SassScript is now an extension of the CSS3 property syntax. All valid CSS3 properties are valid SassScript, and will compile without modification (some invalid properties work as well, such as Microsoft’s proprietary filter syntax). This entails a few changes to SassScript to make it fully CSS3-compatible, which are detailed below.

This also means that Sass will now be fully parsing all property values, rather than passing them through unchanged to the CSS. Although care has been taken to support all valid CSS3, as well as hacks and proprietary syntax, it’s possible that a property that worked in Sass 2 won’t work in Sass 3. If this happens, please report it to the Sass mailing list.

Note that if = is used, SassScript will be interpreted as backwards-compatibly as posssible. In particular, the changes listed below don’t apply in an = context.

The sass-convert command-line tool can be used to upgrade Sass files to the new syntax using the --in-place flag. For example:

# Upgrade style.sass:
$ sass-convert --in-place style.sass

# Upgrade all Sass files:
$ sass-convert --recursive --in-place --from sass2 --to sass stylesheets/
Quoted Strings

Quoted strings (e.g. "foo") in SassScript now render with quotes. In addition, unquoted strings are no longer deprecated, and render without quotes. This means that almost all strings that had quotes in Sass 2 should not have quotes in Sass 3.

Although quoted strings render with quotes when used with :, they do not render with quotes when used with #{}. This allows quoted strings to be used for e.g. selectors that are passed to mixins.

Strings can be forced to be quoted and unquoted using the new unquote and quote functions.

Division and /

Two numbers separated by a / character are allowed as property syntax in CSS, e.g. for the font property. SassScript also uses / for division, however, which means it must decide what to do when it encounters numbers separated by /.

For CSS compatibility, SassScript does not perform division by default. However, division will be done in almost all cases where division is intended. In particular, SassScript will perform division in the following three situations:

  1. If the value, or any part of it, is stored in a variable.
  2. If the value is surrounded by parentheses.
  3. If the value is used as part of another arithmetic expression.

For example:

p
  font: 10px/8px
  $width: 1000px
  width: $width/2
  height: (500px/2)
  margin-left: 5px + 8px/2px

is compiled to:

p {
  font: 10px/8px;
  width: 500px;
  height: 250px;
  margin-left: 9px; }
Variable Defaults

Since = is no longer used for variable assignment, assigning defaults to variables with ||= no longer makes sense. Instead, the !default flag should be added to the end of the variable value. This syntax is meant to be similar to CSS’s !important flag. For example:

$var: 12px !default;

Variable Prefix Character

The Sass variable character has been changed from ! to the more aesthetically-appealing $. For example, what used to be

!width = 13px
.icon
  width = !width

should now be

$width: 13px
.icon
  width: $width

The sass-convert command-line tool can be used to upgrade Sass files to the new syntax using the --in-place flag. For example:

# Upgrade style.sass:
$ sass-convert --in-place style.sass

# Upgrade all Sass files:
$ sass-convert --recursive --in-place --from sass2 --to sass stylesheets/

! may still be used, but it’s deprecated and will print a warning. It will be removed in the next version of Sass, 3.2.

Variable and Mixin Names

SassScript variable and mixin names may now contain hyphens. In fact, they may be any valid CSS3 identifier. For example:

$prettiest-color: #542FA9
=pretty-text
  color: $prettiest-color

In order to allow frameworks like Compass to use hyphens in variable names while maintaining backwards-compatibility, variables and mixins using hyphens may be referred to with underscores, and vice versa. For example:

$prettiest-color: #542FA9
.pretty
  // Using an underscore instead of a hyphen works
  color: $prettiest_color

Single-Quoted Strings

SassScript now supports single-quoted strings. They behave identically to double-quoted strings, except that single quotes need to be backslash-escaped and double quotes do not.

Mixin Definition and Inclusion

Sass now supports the @mixin directive as a way of defining mixins (like =), as well as the @include directive as a way of including them (like +). The old syntax is not deprecated, and the two are fully compatible. For example:

@mixin pretty-text
  color: $prettiest-color

a
  @include pretty-text

is the same as:

=pretty-text
  color: $prettiest-color

a
  +pretty-text

Sass Properties

New-style properties (with the colon after the name) in indented syntax now allow whitespace before the colon. For example:

foo
  color : blue

Sass @import

The Sass @import statement now allows non-CSS files to be specified with quotes, for similarity with the SCSS syntax. For example, @import "foo.sass" will now import the foo.sass file, rather than compiling to @import "foo.sass";.

@extend

There are often cases when designing a page when one class should have all the styles of another class, as well as its own specific styles. The most common way of handling this is to use both the more general class and the more specific class in the HTML. For example, suppose we have a design for a normal error and also for a serious error. We might write our markup like so:

<div class="error seriousError">
  Oh no! You've been hacked!
</div>

And our styles like so:

.error {
  border: 1px #f00;
  background-color: #fdd;
}
.seriousError {
  border-width: 3px;
}

Unfortunately, this means that we have to always remember to use .error with .seriousError. This is a maintenance burden, leads to tricky bugs, and can bring non-semantic style concerns into the markup.

The @extend directive avoids these problems by telling Sass that one selector should inherit the styles of another selector. For example:

.error {
  border: 1px #f00;
  background-color: #fdd;
}
.seriousError {
  @extend .error;
  border-width: 3px;
}

This means that all styles defined for .error are also applied to .seriousError, in addition to the styles specific to .seriousError. In effect, everything with class .seriousError also has class .error.

Other rules that use .error will work for .seriousError as well. For example, if we have special styles for errors caused by hackers:

.error.intrusion {
  background-image: url("/image/hacked.png");
}

Then <div class="seriousError intrusion"> will have the hacked.png background image as well.

How it Works

@extend works by inserting the extending selector (e.g. .seriousError) anywhere in the stylesheet that the extended selector (.e.g .error) appears. Thus the example above:

.error {
  border: 1px #f00;
  background-color: #fdd;
}
.error.intrusion {
  background-image: url("/image/hacked.png");
}
.seriousError {
  @extend .error;
  border-width: 3px;
}

is compiled to:

.error, .seriousError {
  border: 1px #f00;
  background-color: #fdd; }

.error.intrusion, .seriousError.intrusion {
  background-image: url("/image/hacked.png"); }

.seriousError {
  border-width: 3px; }

When merging selectors, @extend is smart enough to avoid unnecessary duplication, so something like .seriousError.seriousError gets translated to .seriousError. In addition, it won’t produce selectors that can’t match anything, like #main#footer.

See also the @extend reference documentation.

Colors

SassScript color values are much more powerful than they were before. Support was added for alpha channels, and most of Chris Eppstein’s compass-colors plugin was merged in, providing color-theoretic functions for modifying colors.

One of the most interesting of these functions is mix, which mixes two colors together. This provides a much better way of combining colors and creating themes than standard color arithmetic.

Alpha Channels

Sass now supports colors with alpha channels, constructed via the rgba and hsla functions. Alpha channels are unaffected by color arithmetic. However, the opacify and transparentize functions allow colors to be made more and less opaque, respectively.

Sass now also supports functions that return the values of the red, blue, green, and alpha components of colors.

HSL Colors

Sass has many new functions for using the HSL values of colors. For an overview of HSL colors, check out the CSS3 Spec. All these functions work just as well on RGB colors as on colors constructed with the hsl function.

Other New Functions

Several other new functions were added to make it easier to have more flexible arguments to mixins and to enable deprecation of obsolete APIs.

Watching for Updates

The sass command-line utility has a new flag: --watch. sass --watch monitors files or directories for updated Sass files and compiles those files to CSS automatically. This will allow people not using Ruby or Compass to use Sass without having to manually recompile all the time.

Here’s the syntax for watching a directory full of Sass files:

sass --watch app/stylesheets:public/stylesheets

This will watch every Sass file in app/stylesheets. Whenever one of them changes, the corresponding CSS file in public/stylesheets will be regenerated. Any files that import that file will be regenerated, too.

The syntax for watching individual files is the same:

sass --watch style.sass:out.css

You can also omit the output filename if you just want it to compile to name.css. For example:

sass --watch style.sass

This will update style.css whenever style.sass changes.

You can list more than one file and/or directory, and all of them will be watched:

sass --watch foo/style:public/foo bar/style:public/bar
sass --watch screen.sass print.sass awful-hacks.sass:ie.css
sass --watch app/stylesheets:public/stylesheets public/stylesheets/test.sass

File and directory watching is accessible from Ruby, using the Sass::Plugin#watch function.

Bulk Updating

Another new flag for the sass command-line utility is --update. It checks a group of Sass files to see if their CSS needs to be updated, and updates if so.

The syntax for --update is just like watch:

sass --update app/stylesheets:public/stylesheets
sass --update style.sass:out.css
sass --watch screen.sass print.sass awful-hacks.sass:ie.css

In fact, --update work exactly the same as --watch, except that it doesn’t continue watching the files after the first check.

sass-convert (née css2sass)

The sass-convert tool, which used to be known as css2sass, has been greatly improved in various ways. It now uses a full-fledged CSS3 parser, so it should be able to handle any valid CSS3, as well as most hacks and proprietary syntax.

sass-convert can now convert between Sass and SCSS. This is normally inferred from the filename, but it can also be specified using the --from and --to flags. For example:

$ generate-sass | sass-convert --from sass --to scss | consume-scss

It’s also now possible to convert a file in-place – that is, overwrite the old file with the new file. This is useful for converting files in the Sass 2 syntax to the new Sass 3 syntax, e.g. by doing sass-convert --in-place --from sass2 style.sass.

--recursive

The --recursive option allows sass-convert to convert an entire directory of files. --recursive requires both the --from and --to flags to be specified. For example:

# Convert all .sass files in stylesheets/ to SCSS.
# "sass2" means that these files are assumed to use the Sass 2 syntax.
$ sass-convert --recursive --from sass2 --to scss stylesheets/

--dasherize

The --dasherize options converts all underscores to hyphens, which are now allowed as part of identifiers in Sass. Note that since underscores may still be used in place of hyphens when referring to mixins and variables, this won’t cause any backwards-incompatibilities.

Convert Less to SCSS

sass-convert can also convert Less files to SCSS (or the indented syntax, although I anticipate less interest in that). For example:

# Convert all .less files in the current directory into .scss files
sass-convert --from less --to scss --recursive .

This is done using the Less parser, so it requires that the less RubyGem be installed.

Incompatibilities

Because of the reasonably substantial differences between Sass and Less, there are some things that can’t be directly translated, and one feature that can’t be translated at all. In the tests I’ve run on open-source Less stylesheets, none of these have presented issues, but it’s good to be aware of them.

First, Less doesn’t distinguish fully between mixins and selector inheritance. In Less, all classes and some other selectors may be used as mixins, alongside more Sass-like mixins. If a class is being used as a mixin, it may also be used directly in the HTML, so it’s not safe to translate it into a Sass mixin. What sass-convert does instead is leave the class in the stylesheet as a class, and use @extend rather than @include to take on the styles of that class. Although @extend and mixins work quite differently, using @extend here doesn’t actually seem to make a difference in practice.

Another issue with Less mixins is that Less allows nested selectors (such as .body .button or .colors > .teal) to be used as a means of “namespacing” mixins. Sass’s @extend doesn’t work that way, so it does away with the namespacing and just extends the base class (so .colors > .teal becomes simply @extend .teal). In practice, this feature doesn’t seem to be widely-used, but sass-convert will print a warning and leave a comment when it encounters it just in case.

Finally, Less has the ability to directly access variables and property values defined in other selectors, which Sass does not support. Whenever such an accessor is used, sass-convert will print a warning and comment it out in the SCSS output. Like namespaced mixins, though, this does not seem to be a widely-used feature.

@warn Directive

A new directive @warn has been added that allows Sass libraries to emit warnings. This can be used to issue deprecation warnings, discourage sloppy use of mixins, etc. @warn takes a single argument: a SassScript expression that will be displayed on the console along with a stylesheet trace for locating the warning. For example:

@mixin blue-text {
  @warn "The blue-text mixin is deprecated. Use new-blue-text instead.";
  color: #00f;
}

Warnings may be silenced with the new --quiet command line option, or the corresponding :quiey Sass option. This option will also affect warnings printed by Sass itself. Warnings are off by default in the Rails, Rack, and Merb production environments.

Sass::Plugin API

Sass::Plugin now has a large collection of callbacks that allow users to run code when various actions are performed. For example:

Sass::Plugin.on_updating_stylesheet do |template, css|
  puts "#{template} has been compiled to #{css}!"
end

For a full list of callbacks and usage notes, see the Sass::Plugin documentation.

Sass::Plugin also has a new method, force_update_stylesheets. This works just like Sass::Plugin#update_stylesheets, except that it doesn’t check modification times and doesn’t use the cache; all stylesheets are always compiled anew.

Output Formatting

Properties with a value and also nested properties are now rendered with the nested properties indented. For example:

margin: auto
  top: 10px
  bottom: 20px

is now compiled to:

margin: auto;
  margin-top: 10px;
  margin-bottom: 20px;

:compressed Style

When the :compressed style is used, colors will be output as the minimal possible representation. This means whichever is smallest of the HTML4 color name and the hex representation (shortened to the three-letter version if possible).

Stylesheet Updating Speed

Several caching layers were added to Sass’s stylesheet updater. This means that it should run significantly faster. This benefit will be seen by people using Sass in development mode with Rails, Rack, and Merb, as well as people using sass --watch from the command line, and to a lesser (but still significant) extent sass --update. Thanks to thedarkone.

Error Backtraces

Numerous bugs were fixed with the backtraces given for Sass errors, especially when importing files and using mixins. All imports and mixins will now show up in the Ruby backtrace, with the proper filename and line number.

In addition, when the sass executable encounters an error, it now prints the filename where the error occurs, as well as a backtrace of Sass imports and mixins.

Ruby 1.9 Support

Firebug Support

A new :debug_info option has been added that emits line-number and filename information to the CSS file in a browser-readable format. This can be used with the new FireSass Firebug extension to report the Sass filename and line number for generated CSS files.

This is also available via the --debug-info command-line flag.

Minor Improvements

2.2.24

Tagged on GitHub.

2.2.23

Tagged on GitHub.

2.2.22

Tagged on GitHub.

2.2.21

Tagged on GitHub.

2.2.20

Tagged on GitHub.

2.2.19

Tagged on GitHub.

There were no changes made to Sass between versions 2.2.18 and 2.2.19.

2.2.18

Tagged on GitHub.

2.2.17

Tagged on GitHub.

Must Read!

2.2.16

Tagged on GitHub.

2.2.15

Tagged on GitHub.

2.2.14

Tagged on GitHub.

SassScript Ruby API

These changes only affect people defining their own Sass functions using Sass::Script::Functions.

Rack Support

Sass 2.2.14 includes Rack middleware for running Sass, meaning that all Rack-enabled frameworks can now use Sass. To activate this, just add

require 'sass/plugin/rack'
use Sass::Plugin::Rack

to your config.ru. See the Sass::Plugin::Rack documentation for more details.

2.2.13

Tagged on GitHub.

There were no changes made to Sass between versions 2.2.12 and 2.2.13.

2.2.12

Tagged on GitHub.

2.2.11

Tagged on GitHub.

2.2.10

Tagged on GitHub.

2.2.9

Tagged on GitHub.

There were no changes made to Sass between versions 2.2.8 and 2.2.9.

2.2.8

Tagged on GitHub.

There were no changes made to Sass between versions 2.2.7 and 2.2.8.

2.2.7

Tagged on GitHub.

There were no changes made to Sass between versions 2.2.6 and 2.2.7.

2.2.6

Tagged on GitHub.

2.2.5

Tagged on GitHub.

There were no changes made to Sass between versions 2.2.4 and 2.2.5.

2.2.4

Tagged on GitHub.

2.2.3

Tagged on GitHub.

Sass 2.2.3 prints line numbers for warnings about selectors with no properties.

2.2.2

Tagged on GitHub.

Sass 2.2.2 is a minor bug-fix release. Notable changes include better parsing of mixin definitions and inclusions and better support for Ruby 1.9.

2.2.1

Tagged on GitHub.

Sass 2.2.1 is a minor bug-fix release.

Must Read!

2.2.0

Tagged on GitHub.

The 2.2 release marks a significant step in the evolution of the Sass language. The focus has been to increase the power of Sass to keep your stylesheets maintainable by allowing new forms of abstraction to be created within your stylesheets and the stylesheets provided by others that you can download and import into your own. The fundamental units of abstraction in Sass are variables and mixins. Please read below for a list of changes:

Must Read!

Sass Syntax Changes

Flexible Indentation

The indentation of Sass documents is now flexible. The first indent that is detected will determine the indentation style for that document. Tabs and spaces may never be mixed, but within a document, you may choose to use tabs or a flexible number of spaces.

Multiline Sass Comments

Sass Comments (//) will now comment out whatever is indented beneath them. Previously they were single line when used at the top level of a document. Upgrading to the latest stable version will give you deprecation warnings if you have silent comments with indentation underneath them.

Mixin Arguments

Sass Mixins now accept any number of arguments. To define a mixin with arguments, specify the arguments as a comma-delimited list of variables like so:

=my-mixin(!arg1, !arg2, !arg3)

As before, the definition of the mixin is indented below the mixin declaration. The variables declared in the argument list may be used and will be bound to the values passed to the mixin when it is invoked. Trailing arguments may have default values as part of the declaration:

=my-mixin(!arg1, !arg2 = 1px, !arg3 = blue)

In the example above, the mixin may be invoked by passing 1, 2 or 3 arguments to it. A similar syntax is used to invoke a mixin that accepts arguments:

div.foo
  +my-mixin(1em, 3px)

When a mixin has no required arguments, the parenthesis are optional.

The default values for mixin arguments are evaluated in the global context at the time when the mixin is invoked, they may also reference the previous arguments in the declaration. For example:

!default_width = 30px
=my-fancy-mixin(!width = !default_width, !height = !width)
  width= !width
  height= !height

.default-box
  +my-fancy-mixin

.square-box
  +my-fancy-mixin(50px)

.rectangle-box
  +my-fancy-mixin(25px, 75px)

!default_width = 10px
.small-default-box
  +my-fancy-mixin

compiles to:

.default-box {
  width: 30px;
  height: 30px; }

.square-box {
  width: 50px;
  height: 50px; }

.rectangle-box {
  width: 25px;
  height: 75px; }

.small-default-box {
  width: 10px;
  height: 10px; }

Sass, Interactive

The sass command line option -i now allows you to quickly and interactively experiment with SassScript expressions. The value of the expression you enter will be printed out after each line. Example:

$ sass -i
>> 5px
5px
>> 5px + 10px
15px
>> !five_pixels = 5px
5px
>> !five_pixels + 10px
15px

SassScript

The features of SassScript have been greatly enhanced with new control directives, new fundamental data types, and variable scoping.

New Data Types

SassScript now has four fundamental data types:

  1. Number
  2. String
  3. Boolean (New in 2.2)
  4. Colors

More Flexible Numbers

Like JavaScript, SassScript numbers can now change between floating point and integers. No explicit casting or decimal syntax is required. When a number is emitted into a CSS file it will be rounded to the nearest thousandth, however the internal representation maintains much higher precision.

Improved Handling of Units

While Sass has long supported numbers with units, it now has a much deeper understanding of them. The following are examples of legal numbers in SassScript:

0, 1000, 6%, -2px, 5pc, 20em, or 2foo.

Numbers of the same unit may always be added and subtracted. Numbers that have units that Sass understands and finds comparable, can be combined, taking the unit of the first number. Numbers that have non-comparable units may not be added nor subtracted – any attempt to do so will cause an error. However, a unitless number takes on the unit of the other number during a mathematical operation. For example:

>> 3mm + 4cm
43mm
>> 4cm + 3mm
4.3cm
>> 3cm + 2in
8.08cm
>> 5foo + 6foo
11foo
>> 4% + 5px
SyntaxError: Incompatible units: 'px' and '%'.
>> 5 + 10px
15px

Sass allows compound units to be stored in any intermediate form, but will raise an error if you try to emit a compound unit into your css file.

>> !em_ratio = 1em / 16px
0.063em/px
>> !em_ratio * 32px
2em
>> !em_ratio * 40px
2.5em

Colors

A color value can be declared using a color name, hexadecimal, shorthand hexadecimal, the rgb function, or the hsl function. When outputting a color into css, the color name is used, if any, otherwise it is emitted as hexadecimal value. Examples:

> #fff
white
>> white
white
>> #FFFFFF
white
>> hsl(180, 100, 100)
white
>> rgb(255, 255, 255)
white
>> #AAA
#aaaaaa

Math on color objects is performed piecewise on the rgb components. However, these operations rarely have meaning in the design domain (mostly they make sense for gray-scale colors).

>> #aaa + #123
#bbccdd
>> #333 * 2
#666666

Booleans

Boolean objects can be created by comparison operators or via the true and false keywords. Booleans can be combined using the and, or, and not keywords.

>> true
true
>> true and false
false
>> 5 < 10
true
>> not (5 < 10)
false
>> not (5 < 10) or not (10 < 5)
true
>> 30mm == 3cm
true
>> 1px == 1em
false

Strings

Unicode escapes are now allowed within SassScript strings.

Control Directives

New directives provide branching and looping within a sass stylesheet based on SassScript expressions. See the Sass Reference for complete details.

@for

The @for directive loops over a set of numbers in sequence, defining the current number into the variable specified for each loop. The through keyword means that the last iteration will include the number, the to keyword means that it will stop just before that number.

@for !x from 1px through 5px
  .border-#{!x}
    border-width= !x

compiles to:

.border-1px {
  border-width: 1px; }

.border-2px {
  border-width: 2px; }

.border-3px {
  border-width: 3px; }

.border-4px {
  border-width: 4px; }

.border-5px {
  border-width: 5px; }

@if / @else if / @else

The branching directives @if, @else if, and @else let you select between several branches of sass to be emitted, based on the result of a SassScript expression. Example:

!type = "monster"
p
  @if !type == "ocean"
    color: blue
  @else if !type == "matador"
    color: red
  @else if !type == "monster"
    color: green
  @else
    color: black

is compiled to:

p {
  color: green; }

@while

The @while directive lets you iterate until a condition is met. Example:

!i = 6
@while !i > 0
  .item-#{!i}
    width = 2em * !i
  !i = !i - 2

is compiled to:

.item-6 {
  width: 12em; }

.item-4 {
  width: 8em; }

.item-2 {
  width: 4em; }

Variable Scoping

The term “constant” has been renamed to “variable.” Variables can be declared at any scope (a.k.a. nesting level) and they will only be visible to the code until the next outdent. However, if a variable is already defined in a higher level scope, setting it will overwrite the value stored previously.

In this code, the !local_var variable is scoped and hidden from other higher level scopes or sibling scopes:

.foo
  .bar
    !local_var = 1px
    width= !local_var
  .baz
    // this will raise an undefined variable error.
    width= !local_var
  // as will this
  width= !local_var

In this example, since the !global_var variable is first declared at a higher scope, it is shared among all lower scopes:

!global_var = 1px
.foo
  .bar
    !global_var = 2px
    width= !global_var
  .baz
    width= !global_var
  width= !global_var

compiles to:

.foo {
  width: 2px; }
  .foo .bar {
    width: 2px; }
  .foo .baz {
    width: 2px; }

Interpolation

Interpolation has been added. This allows SassScript to be used to create dynamic properties and selectors. It also cleans up some uses of dynamic values when dealing with compound properties. Using interpolation, the result of a SassScript expression can be placed anywhere:

!x = 1
!d = 3
!property = "border"
div.#{!property}
  #{!property}: #{!x + !d}px solid
  #{!property}-color: blue

is compiled to:

div.border {
  border: 4px solid;
  border-color: blue; }

Sass Functions

SassScript defines some useful functions that are called using the normal CSS function syntax:

p
  color = hsl(0, 100%, 50%)

is compiled to:

#main {
  color: #ff0000; }

The following functions are provided: hsl, percentage, round, ceil, floor, and abs. You can define additional functions in ruby.

See Sass::Script::Functions for more information.

New Options

:line_comments

To aid in debugging, You may set the :line_comments option to true. This will cause the sass engine to insert a comment before each selector saying where that selector was defined in your sass code.

:template_location

The Sass::Plugin :template_location option now accepts a hash of sass paths to corresponding css paths. Please be aware that it is possible to import sass files between these separate locations – they are not isolated from each other.

Miscellaneous Features

@debug Directive

The @debug directive accepts a SassScript expression and emits the value of that expression to the terminal (stderr).

Example:

@debug 1px + 2px

During compilation the following will be printed:

Line 1 DEBUG: 3px

Ruby 1.9 Support

Sass now fully supports Ruby 1.9.1.

Sass Cache

By default, Sass caches compiled templates and partials. This dramatically speeds up re-compilation of large collections of Sass files, and works best if the Sass templates are split up into separate files that are all @imported into one large file.

Without a framework, Sass puts the cached templates in the .sass-cache directory. In Rails and Merb, they go in tmp/sass-cache. The directory can be customized with the :cache_location option. If you don’t want Sass to use caching at all, set the :cache option to false.