Rebooting CSS Variables [CSS Custom Properties]

Many subjects are being discussed in the CSS Working Group. So many subjects, in fact, that you can't get involved in all of them. However, some are more critical to the future of the CSS language than others. And I truly believe that the current css-variables discussion is one of them.

Because of its unique scope, because it's a so long-requested feature and because it going to enable a whole new range of usages, the css-variables spec is really a big deal. However, early publication efforts clearly show that most web developers are not getting the soul of the new specification.

Because they compare css-variables to preprocessor variables (read: SASS, LESS, PHP...), most developers fail to notice all the greatness of this new specification, criticize its choices and conclude they will stick with SASS variables for now.

In fact, nobody is encouraging developers to move away from preprocessor variables. The css-variables goal is not to replace preprocessor variables, because the use cases they cover will always be preferentially done server-side.

Server-side variables bring the ease of use of macros to developers while keeping the CSS syntax simple and easy to parse. As such they don't impact client-side rendering performance. Because they don't depend on client-side features, they are also able to evolve at astonishing speeds, and to adapt to developers needs very quickly.

What css-variables have become is fundamentally different from them. To be accepted in the very select CSS world, css-variables had to bring something new; something that preprocessor variables weren't able to provide: their dynamic nature.

The CSS Custom Properties specification is based on the latest and greatest css-variables specification, but marks a clear break with the past by not calling them using name they don't deserve, and by giving them a syntax that best fit their needs.

Custom Properties

The first concept introduced by this specification is called custom properties. By custom properties, we mean properties inherited through the CSS cascade but which don't carry any particular meaning other than the one it's author given him.

.selector {
my-property: value;
}

You can recognize custom properties easily: the same way custom HTML attributes all start with a data prefix, CSS custom properties are going to start with a my prefix. To the contrary of HTML data attributes, CSS custom properties are feeling truly personal, and this is something developers are going to enjoy every time they will be using them.

With custom properties, authors are going to be able to shim unimplemented CSS properties in a way that doesn't overlap with the native implementations, yet using the full power of CSS Selectors and at a reduced cost.

Because they are properties like any other, custom properties behave just like the CSS properties you all know, and hopefully like. They cascade, they inherit, they are straightforward to define in your CSS files, in your HTML, in your JavaScript code. In fact, they are anywhere you need them, anywhere you want them, seamlessly integrated with the tools you love.

The concept of custom properties is really well understood by the web community, as can testimonial multiple stackoverflow threads asking why something as simple as custom properties isn't working by default in today's browsers. The my syntax is very natural to them, more than one of the threads use it even if it wasn't necessary nor used in any known specification or blog post.

As the concept emerged naturally in the developer community and seems well understood, calling custom properties anything else than custom properties would be a huge mistake, in our opinion.

References

The second concept introduced by this specification is easily explained using an analogy with the data-binding pattern. Modern MVC applications are mapping the custom properties of their data objects to framework-provided properties and tags which are able to materialize on the screen.

With the introduction of custom properties, the CSS WG envisions that bindings between traditional, framework-provided properties and the custom ones are going to be a very used feature.

The CSS Custom Properties specification's first sample is showing how powerful CSS references are going to be. You can use document-wide meta-properties to store in a dynamic way important data about your document layout, like color palette or font treatments, and you can react to Media Queries change and other client-side information.

But, wait, there's more. You can update those properties while the page is loaded, and you can access them by script. You can also define variables or override them just for sections of your page. Each time you change them, the change propagate automatically to any place it's actually used.

A very good way to understand how useful it is, is by seeing how HTML Components can actually benefit from them. I therefore invite you to have a look at the second sample of the specification. It shows why custom properties, while having the same expressive power as traditional preprocessor variables, are able to cover much more use cases.

That's why talking about them as 'variables' is so wrong: they are not variables. Variables are just a place where you can store data in your program. When you're actually using the value of a custom property somewhere, you're not just using a variable, you're actually referencing a property: you provide both a target object and a property name; it means you can actually track changes in real time, something variables don't allow you to do.

I argue it's far easier to explain someone how css-variables work by starting from a custom-property/reference point of view than trying to explain why css-variables are so different from the kind of variables they know and are used to.

Providers

While CSS Token Substitution is not all about referencing properties, as we shall see in this section, it's clear to that even referencing properties is more challenging that you may think.

Sometimes, you may want to use the value of a property as it was defined on the parent to compute its new value. This is for example the case in the font-size property, when you use relative units like percentages. There's no reason to expect that it will be different in the case of custom properties. This is why the $parent provider allow you to retrieve the value of a property as it was on the current element's parent.

Sometimes, you also want custom properties that don't inherit. As the browser don't know about your properties, it's impossible for it to know if you want a property to inherit or not. By default, we made the choice to activate inheriting by default. However, by using the $element provider, CSS will only use the value of a property if it was explicitly defined on the current element, allowing you to mimic non-inherited properties.

We certainly expect (and hope) that more providers will be introduced over time. For example, the $host provider could allow you to retrieve the value a property has on the host of the current Shadow DOMTree, a newly introduced concept for HTML Components.

We also envision providers like $attr, which will allow you to use the value defined in HTML attributes as a value for your CSS properties, unlike the attr() function which is return a <string>.

As you can see, references are more than just variables: they show a very impressive extensibility that we certainly are going to use it in the future.

One syntax to rule them all

Because this specification introduces so many things doesn't mean it has to introduce a cryptic or inconsistent syntax. Reusing the assets of existing programmers has been very important for us when crafting the CSS Custom Properties draft.

For the same reason we choose the my prefix because it looked intuitive to most developers, we choose to use the dollar symbol ($) to indicate substitutions. Substitutions are more than simple functions, because they have a far broader scope and are agnostic to the content they carry. 

$provider(name, fallback value)

Developers around the world can easily guess that $(foo) is going to be replaced by the value of foo at computation time. And this is exactly what this thing is doing.

The syntax is also very consistent and you don't need to change anything if you need to add a fallback value later on. Syntax stability is an important feature of a good syntax because it means that refactoring will be easier.

Here's a glimpse at the syntax in its full glory:

.selector {

my-color: red;
my-color-backup: $parent(my-color,red);

color: $(my-color);
}

Using a well understood syntax and sticking to the principles I developed in my June 4 summary make the CSS Custom Properties specification a true game changer, and I really hope it will get the treatment it deserves.

Thank you!

Now, I encourage you to read the specification, if you haven't done already and to leave a comment about what you think of it!

Published on 2012-06-26 under ALL, CSS, WEB

Comments

A javascript file is loading the comments.