Sass 3.5 Release Candidate
Posted 30 August 2016 by Natalie Weizenbaum
I’ve just pushed the button to release Sass 3.5.0-rc.1. If it seems like it’s been a while since the last release, that’s true! But there’s a good reason. We decided to enter feature freeze after the 3.5 release to give libsass, the super-speedy C++ implementation of Sass, time to reach feature parity with Sass 3.4. Libsass is much younger than Sass, and C++ is generally a slower language to work in than Ruby, so this took some time. But it paid off: libsass is now almost 100% compatible with Ruby Sass, differing only in a few small bugs.
After the feature freeze lifted, we were primarily focused on designing the new module system that will be the central feature of Sass 4.0. But we also found some time to add some new features, which are the focus of this release.
CSS Custom Property SupportCSS Custom Property Support permalink
Sass 3.5 now fully supports CSS custom properties. These posed a particular challenge for us, since the custom property syntax is extremely broad. You can put just about anything on the right-hand side. For example, this is totally valid, meaningful CSS:
.wacky-property {
--property: .%(#@$~`^[^_+]<;:"}"|?)*+;
}
In particular, this means that SassScript expressions are also valid CSS, which poses a problem for our goal of CSS compatibility. Wherever possible, we want valid CSS to mean the same thing in Sass as it does in CSS. So treating custom properties just like normal properties—which we did in 3.4—wasn’t a good solution. Not only was some valid CSS interpreted differently, some of it wasn’t even possible. The following CSS, taken straight from the Polymer docs, was next to impossible to represent in Sass:
:host {
--my-toolbar-theme: {
background-color: green;
border-radius: 4px;
border: 1px solid gray;
}
}
On the other hand, we needed some way of including dynamic SassScript values
in custom properties. So we decided on a compromise: we’d treat custom
properties like we do selectors and at-rule values, and only allow #{}
as a
means of including Sass values. While technically this is plain CSS, it’s a very
small surface area and it’s very easy to escape, so we’re not too worried. This
means that in 3.5 you can write:
:host {
--my-toolbar-theme: {
background-color: #{$toolbar-background};
border-radius: 4px;
border: 1px solid gray;
}
}
New Data Type: First-Class FunctionsNew Data Type: First-Class Functions permalink
In preparation for the module system that’s coming in Sass 4.0, 3.5 adds a new
data type: first-class functions. This is just a way of referring to a function
that’s more specific than just its name. You can get a first-class function by
passing its name to get-function($name)
, and you can pass it to call()
where
you used to pass the function name.
You might be wondering, "Why is this useful? I could already just pass the
function name." Well, right now, Sass has global scope. All functions (as well
as variables, mixins, and selectors) are visible to any code that’s executing
later on. This makes some things, like call()
, simple, but it also causes a
lot of problems. It’s way too easy to accidentally overwrite a variable or
function that was defined elsewhere, and it’s way too hard to figure out where
any given name was originally defined.
We aren’t quite ready to talk widely about our plans for the 4.0 module system, but one of the things we’re sure of is that it won’t use global scope. Each Sass file will only be able to see a limited number of the names that have been defined, and Sass libraries in particular won’t be able to see anything defined by the end-user stylesheets that import them. First-class functions allow users to pass functions they define to libraries.
Any stylesheets that are currently passing around function names as strings
should switch to passing first-class functions instead. To this end, calling
call()
with a string has been deprecated. It won’t actually break until 4.0,
when it won’t be much use anyway, but we strongly encourage users to switch to
get-function()
immediately.
New Syntax: Bracketed ListsNew Syntax: Bracketed Lists permalink
The new CSS Grid Layout module added a new type of syntax: identifiers surrounded by square brackets. We’re always striving to be totally compatible with CSS, which meant we needed to support these brackets as well. Here’s what they look like in CSS:
.container {
grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
}
The solution was clear: Sass already has a list data
type, so we’d just allow lists
to have square brackets. So [first]
is just a list containing the unquoted
string first
. Like all Sass lists, bracketed lists can either be
space-separated or comma-separated: [foo bar baz]
and [foo, bar, baz]
are
both lists containing three elements.
We’ve also added function support for bracketed lists. The is-bracketed($list)
function returns whether a list is bracketed or not, and join()
has a new
$bracketed
parameter that allows the caller to choose whether or not the
resulting list will have brackets (by default, the result is bracketed if the
first list is).
Smaller FeaturesSmaller Features permalink
We’ve added a content-exists()
function that returns whether or not a content
block was passed to the current mixin. This allows mixins to optionally take a
content block, rather than having to define one mixin that takes content and one
that does not.
We’ve added the ability to add a trailing comma to argument lists. This matches the behavior of lists and maps.
We’ve added a $weight
parameter to the invert()
function. This is a
percentage between 0% and 100% that indicates how inverted the resulting color
should be. It defaults to 100%.
The Road to ReleaseThe Road to Release permalink
This is just a release candidate, but it’s in a place that we’d be happy shipping it as the final release. We’re not doing so because, now that we’ve reached feature compatibility with libsass, we’re committed to staying there.
Unfortunately, since Marcel Greter moved on from the project, libsass has been moving pretty slowly lately. If you or anyone you know would be interested in working on a project that would benefit thousands of people, we’re still looking for new contributors!
Until we have libsass compatibility, 3.5 will stay at a release candidate level. But don’t let that stop you from trying it out and letting us know what you think! We’re always interested in hearing feedback on the mailing list!