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!