About Variables in CSS and Abstractions in Web Languages

Published by Chris Coyier

Variables are coming to CSS. They already have implementations, so there is no stopping it now. Firefox has them in version 29 and Chrome has them unprefixed in 29+ if you have the "Enable experimental Web Platform features" flag turned on.

To be clear, no amount of arguing on whether this is good or bad is going to change things at this point. But I still think it's interesting, so let's talk about it anyway.

The Abstraction Backstory

I've been giving a talk recently about abstraction in computing. Looking back at the history of programming, there are several clear points where we stepped up abstraction to a new level. From the "1's and 0's" of machine code, to assembler languages, to compilers, and the abstractions of those giving us languages like C++.

Browsers are comprised of parts, like a rendering engine and a JavaScript engine. Those parts are written in C++. So when we write things like HTML, CSS, and JavaScript, we're yet another step up the abstraction ladder. HTML, CSS, and JavaScript don't replace the languages below them, they sit on top of them. They depend on the layers below to do the things they do best. HTML, CSS, and JavaScript are languages we invented in order to build the kind of things we wanted to build on the web: interactive documents.

As time goes on, we want/expect/need the web platform to do more. Capabilities are only ever added to browsers, never removed. We gobble up those new capabilities and use them to their limits. That makes building for the web more complex. We don't like complexity. It makes work harder and less efficient.

This has been going on long enough that we're taking that next step up the abstraction ladder. Abstraction is the natural combatant to complexity, so we employ abstraction to lower the complexity of the code we write.

The abstraction we most needed on the web was for HTML. It would be ridiculous to work on a website where every page was stored as a complete HTML document, from <!DOCTYPE html> to </html> that you edited directly. No one works that way anymore. Complete HTML documents are pieced together through templates and chunks of content.

Abstraction in JavaScript is inherent. The tools of abstraction are already there. Variables, loops, functions, etc.

The last web language to get the abstraction treatment is CSS, and that has come in the form of preprocessors. CSS is enormously repetitive and offers almost no abstraction tools. Preprocessors offer those things that we need so desperately and save the day.

Popularity

Another thing at work here is the popularity of the web platform. It is the most successful platform ever in computers. More people build for it and use the things built from it than any other. In other words, HTML, CSS, and JavaScript are pretty damn successful. Largely due to the work of the efforts of web standards advocates, but that's a story for another day.

Why is a language like CSS so damn successful? Because it is so easy. Selectors and key/value pairs. That's it. Yes, there are lots of little gotchas as nuances. Yes, it takes a long time to really master. But the root language is very simple. In ten seconds you can show someone a block of code and explain how it works in such a way they completly get it.

h1 {
  color: red;
}

I'm convinced CSS is as successful as it is because of how easy the syntax is to understand, learn, and teach. There is plenty to bitch about in CSS, but I think correct language choices were made early on.

Complicating the Core Language

As languages do, CSS has evolved over time. Like everything in the web platform, it added new capabilities. Jeremey Keith pointed out that @keyframes represent a significant shift in CSS. For the first time, you could write CSS that had no meaning and wouldn't work at all if not for another block of CSS elsewhere in the code.

/* This means nothing... */
.animate {
  animation: my-animation 0.2s;
}

/* ...if not for this, which could be anywhere or nowhere */
@keyframes my-animation {
  to { color: red; }
}

As Jeremy says:

So CSS variables (or custom properties) aren't the first crack in the wall of the design principles behind CSS. To mix my metaphors, the slippery slope began with @keyframes (and maybe @font-face too).

A given chunk of CSS is no longer guaranteed to have meaning.

CSS (the core language) is heading down the path of being fully programmatic. If variables are useful, surely loops are as well, right? We can start to imagine a version of CSS that has so many powerful programming capabilities that it no longer feels like that simple, easy, understandable language it came from. That simplicity that made it successful to begin with.

The Abstraction Layer

I'm absolutely not anti-variables or anti-any-programming-concept. I love these things. They empower me as an author, making my job easier and enabling me to do more. That's what all (good) abstraction layers do. So why not leave these concepts in the abstraction layer rather than alter the core principles of the language?

Again as Jeremy says:

Thanks to preprocessors like Sass, we can have our cake and eat it too.

Not All Abstractions Are Great

In the spirit of back-and-forth blogging, allow me to respond to Jeremy again.

...not all abstractions are good abstractions.

He goes on to compare Sass and Haml, declaring Sass good and Haml bad. I'm largely in agreement there. I've worked with Haml a little and have never extracted much value from it, while I extract loads of value every day from Sass. I have two points to make here.

Chris made the case for abstractions being inherently A Good Thing.

The context here needs to be "over time". When these points in history come along where we step up the abstraction ladder, there are always languages that compete for that place in history. Developers duke it out (as we're seeing now with the CSS preprocessor market) and as the years go by a "winner" emerges with the vast majority of "market share" if such a term applies here.

The winners are A Good Thing as they have proven themselves. The losers were (probably) the less-good abstractions.

My second point is that I believe there is a such thing as a primary abstraction and secondary abstractions. Perhaps those aren't excellent terms, but what I mean is that there is an abstraction that provides the most important and valuable things authors need (the primary abstraction) then there are abstractions that provide little niceties (secondary abstractions).

As mentioned above, the primary abstraction of HTML is templates and content stored in data-stores. Haml is a secondary abstraction providing a more comfortable syntax for developers of certain flavors. CoffeeScript is also a secondary abstraction to JavaScript's inherent tools of abstraction.

Sass (or whatever the winner turns out to be over time) is the primary abstraction for CSS.