CSS Variables in Firefox 29

  ·   One of the most frequent requests to the CSS Working Group over the years has been to have some kind of support for declaring and using variables in style sheets. After much discussion, the CSS Custom Properties for Cascading Variables specification took the approach of allowing the author to specify custom properties in style rules that cascade and inherit as other inherited properties do. References to variables can be made in property values using the var() functional syntax.

Custom properties that declare variables all must be named beginning with var-. The value of these custom properties is nearly freeform. They can take nearly any stream of tokens, as long as it is balanced.

For example, an author might declare some common values on a style rule that matches the root element, so that they are available on every element in the document:

:root {
  var-theme-colour-1: #009EE0; 
  var-theme-colour-2: #FFED00; 
  var-theme-colour-3: #E2007A; 
  var-spacing: 24px;
}

Variables can be referenced at any position within the value of another property, including other custom properties. The variables in the style sheet above can be used, for example, as follows:

h1, h2 {
  color: var(theme-colour-1);
}
h1, h2, p {
  margin-top: var(spacing);
}
em {
  background-color: var(theme-colour-2);
}
blockquote {
  margin: var(spacing) calc(var(spacing) * 2);
  padding: calc(var(spacing) / 2) 0;
  border-top: 2px solid var(theme-colour-3);
  border-bottom: 1px dotted var(theme-colour-3);
  font-style: italic;
}

When applied to this document:

<!DOCTYPE html>
<h1>The title of the document</h1>
<h2>A witty subtitle</h2>
<p><em>Please</em> consider the following quote:</p>
<blockquote>Text of the quote goes here.</blockquote>

the result would be something that looks like this:

The title of the document
A witty subtitle
Please consider the following quote:
Text of the quote goes here.

Variables are resolved based on the value of the variable on the element that the property with a variable reference is applied to. If the h2 element had a style="var-theme-colour-1: black" attribute on it, then the h2 { color: var(theme-colour-1); } rule would be resolved using that value rather than the one specified in the :root rule.

Variable references can also include fallback to use in case the variable is not defined or is invalid (due to being part of a variable reference cycle). The first rule in the style sheet using the variables could be rewritten as:

h1, h2 {
  color: var(theme-colour-1, rgb(14, 14, 14));
}

which would result in the colour being a dark grey if the theme-colour-1 variable is not defined on one of the heading elements.

Since variable references are expanded using the variable value on the element, this process must be done while determining the computed value of a property. Whenever there is an error during the variable substitution process, it causes the property to be “invalid at computed-value time”. These errors can be due to referencing an undeclared variable with no fallback, or because the substituted value for the property does not parse (e.g. if we assigned a non-colour value to the theme-colour-1 variable and then used that variable in the ‘color’ property). When a property is invalid at computed-value time, the property declaration itself is parsed successfully and will be visible if you inspect the CSSStyleDeclaration object in the DOM. The computed value of the property will take on a default value, however. For inherited properties, like ‘color’, the default value will be ‘inherit’. For non-inherited properties, it is ‘initial’.

Implementation

An initial implementation of CSS Variables has just landed in Firefox Nightly, which is currently at version 29. The feature is not yet enabled for release builds (that is, Firefox Beta and the release version of Firefox), as we are waiting for a few issues to be resolved in the specification and for it to advance a little further in the W3C Process before making it more widely available. It will however continue to be available in Nightly and, after the February 3 merge, in Firefox Aurora.

The only part of the specification that has not yet been implemented is the CSSVariableMap part, which provides an object that behaves like an ECMAScript Map, with get, set and other methods, to get the values of variables on a CSSStyleDeclaration. Note however that you can still get at them in the DOM by using the getPropertyValue and setProperty methods, as long as you use the full property names such as "var-theme-colour-1".

The work for this feature was done in bug 773296, and my thanks to David Baron for doing the reviews there and to Emmanuele Bassi who did some initial work on the implementation. If you encounter any problems using the feature, please file a bug!


Six comments

You can subscribe to the comment feed to follow the responses to this entry.

  1. Robert O'Callahan
    14 December 2013, 10:48pm

    Great stuff! This, plus Web Components stuff landing, should really help people write reusable code on the Web.

    You should get this uplifted to the hacks blog.

  2. Writing a blog post for hacks to release tomorrow. In the future, we’d be very happy to publish this on the hacks post, especially when the quality of the post is this good. Rob: “uplifted”? Reposting means we already lost a lot of traffic and is actually punished by Google. :)

  3. I’m sad that my very first idea for using this found bug 950436

  4. I don’t think it is a good idea to put the opportunity to write variables directly into CSS. I think it should stay in the pre-processor world. Jeremy Keith has written down his thoughts about this topic in this post: http://adactio.com/journal/6606/?utm_source=CSS-Weekly&utm_campaign=Issue-90&utm_medium=email and I share a lot of them.

  5. Next up, CSS nesting! (almost like LESS and Sass allow)
    .a{
    .b{
    color:white;
    }
    }
    Equivalent to:
    .a .b{
    color:white;
    }

  6. Great Post. Very interesting using variables, but it would become very much a developers language. Also, as interesting as it seems, it won’t be used as much since most browsers will not support this kind of styles.

Leave a comment