Everything In Between

If your project so much as pretends to have a profit motive, I will tell you to go fuck yourself and your project.

Why CSS needs delegation capabilities and not “variables”

18 comments

It’s been too long since I joined the fun, if amazingly heated, debates over the direction that Web standards are moving in. Recently, given the “free” time to do so, I decided to dive head first into what is (sadly) an almost 14 year old debate. The result is this blog post, which is mostly a response to Bert Bos’s essay Why “variables” in CSS are harmful and Matt Wilcox’s opposing response to that essay, Why CSS needs to borrow from programming languages. Their articles are each worthy of a read, possibly before this one.

Here’s the summary of my argument.

Adding many “programmatic” features to the CSS language such as variables, macros, or flow control is a mistake. However, CSS’s failure to simply encode visual relationships (instead of merely typographic properties)—a severe deficiency in the core language itself—requires the addition of delegation features. With the additional capability to reference an arbitrary element’s computed value regardless of its hierarchical context, CSS will be more accessible to both amateur and professional web designers, more capable, and will more forcefully promote the semantic Web and its ideals.

In this corner: CSS variables are harmful

Bert does a great job of summarizing the conclusion of his argument himself. In his essay, Bert says:

Adding any form of macros or additional scopes and indirections, including symbolic constants, is not just redundant, but changes CSS in ways that make it unsuitable for its intended audience. Given that there is currently no alternative to CSS, these things must not be added.

As we all know, one of the wonderful things about CSS is that the core language itself is remarkably simple. (What’s not simple is the spectacular way browser manufacturers have destroyed everyone’s hope that implementing CSS-based designs in the real world will ever be easy, but that’s a whole different can of worms.) Fundamentally, CSS’s syntax can be explained with a mere three major components: property/value pairs, declaration blocks, and rule sets.

What this means is that CSS as a language is stupidly easy to learn. I think everyone would agree that it’s certainly easier to learn than, say, JavaScript or XSL. Now, that’s important because, without putting too fine a point on it, Bert mentions multiple times that CSS’s “intended audience” are the diverse and likely relatively technically ignorant content authors that are responsible for the overwhelming majority of web pages on the public Internet today.

He makes the very good point that The value of the semantic Web isn’t defined by how well structured the best documents are, but by how well structured the vast majority of documents are. In other words, CSS needs to remain instantly useable and reusable to these untrained, amateur web content publishers for the benefits of self-describing documents (i.e., the semantic Web) to see mass adoption.

To wit:

reusing other people’s style sheets is more difficult if those style sheets contain user-defined names. Class names are an example. Their names may suggest why the author created them (assuming they are in a language you understand), but typically you will have to look at the document to see where they occur and why. Symbolic constants make that problem worse.

And, later:

For many people, style sheets with constants will thus simply not be usable. It is too difficult to look in two places at once, the place where a value is used and the place where it is defined, if you don’t know why the rule is split in this way. Many people are confused by indirection anyway and adding an extra one, in addition to the element and class names, has the same effect as obfuscating the style sheet.

Whether or not you believe Bert Bos is underestimating the average web designer, it’s pretty clear that these are really good points. Nobody wants CSS to be obfuscated, hard to learn, or hard to reuse. That’d just be crazy talk.

In the other corner: CSS variables are a real-world requirement

The more features you add to an application, a programming language, or indeed any software, the more difficult it becomes to grok it. As the Python people would say, the larger a language gets the more difficult it is to hold all of it in your head. Nevertheless, adding “features” is sometimes the only way to add capabilities, and I don’t think anyone in their right mind would argue that, once written, software should never change. (That’d just be crazy talk, too.)

In his opposing arguments, Matt Wilcox recognizes this when he says, Yes, the syntax should be simple, but the capabilities of CSS should not. What he’s alluding to without verbalizing it is the balance between adding necessary capabilities without unnecessarily growing the “size of the language.”

However, Matt says that modern web design methodologies (e.g., separation of concerns between structure, presentation, and behavior) dictate that CSS needs more capabilities than it currently has:

CSS lacks capabilities to allow truly flexible design, requiring layer upon layer of ‘tricks’ to accomplish certain objectives, requiring content to be structured ‘just so’ to achieve a display objective, or in the case of some designs proving instead to be completely incapable.

[…]

CSS’s positioning is a cludge. It’s a cludge because you can only position relative to the last positioned parent container. Well, that limitation in itself dictates that all positioning relies upon how the content is structured. And that means the presentation and the content are not truly separable.

To align CSS’s capabilities with the requirements of real-world web design objectives, he says, CSS needs to be capable of describing relationships between semantically and structurally arbitrary but visually related elements.

Visual design is fundamentally about relationships between elements. For all of the artistic flourishes and creativity, it’s about relationships. ‘That yellow’ only grabs your attention because of its contrasting relationship with ‘that blue’. ‘This heading’ only works as a heading because of it’s exaggerated relationship to the size of the body text. […] CSS has no clue about relationships, period. And that’s why CSS as it stands right now, is not good enough. That’s why CSS without variables (true variables), without basic logic, without maths, can never be as flexible as we need it to be.

This is what web designers have been complaining about for (what feels like hundreds of) years. The fact that CSS has no capability to describe presentational relationships between elements in addition to directly describing an individual element’s presentational properties is a gaping hole that sorely degrades its ability to be a media-agnostic styling language. Every single web designer I’ve worked with has gasped at this omission, and though at first I didn’t understand why, the more I understood the principles behind graphic design the more I came to realize how fundamentally problematic this omission really is.

Adding delegation makes CSS easier for designers

As Matt eloquently stated, design is all about relationships. Good web designers create designs by constructing visual elements that have strong, often exacting relationships with other visual elements. There are many names and examples for this: visual language, visual hierarchy, the golden ratio, the grid, visual balance, the typographer’s scale, and so on.

What happens when the designer tries to define a relationship between elements? “How do I say that the whitespace between element A and element B should always be the same? How do I define element A’s height as half of element B’s?” These definitions, which are natural and necessary to the way designers work in both their mind and their mediums, are impossible to encode in CSS.

The closest you can get is declaring the same values to each element’s properties, not describing the relationship itself. This suffices only so long as these values are known ahead of time and are the same as one another, which severely limits the design possibilities we are capable of (without resorting to what Matt calls “tricks”). That’s why achieving simple visual effects are actually very complex and so, sadly, that’s where you’ll find the majority of indirection and obfuscation in CSS today. (I’m looking at you, faux columns.)

So who wins?

Both Bert Bos and Matt Wilcox have made some great points. Bert rightfully wishes to keep CSS lean and simple, even at the expense of some arguably beneficial styling power. Matt, on the other hand, argues that our needs as web designers have evolved faster than the technology to the point where CSS is too limited, fundamentally so.

The truth is, they’re both right. And they’re both wrong. Or rather, they are each taking a position that is too extreme. Bert’s absolutely correct when says that many of these proposed extensions are redundant and harmful, and yet Matt’s also correct that CSS lacks some fundamental capabilities that designers expect to be present.

Bert says that the CSS capabilities everyone’s asking for can be implemented using techniques that don’t rely on CSS whatsoever. These techniques, he says, make things like true CSS variables “redundant.”

There are examples of CSS with constants to satisfy all styles of programming, e.g.: David Walsh (in PHP), Tedd Sperling (in PHP), Digital Web Magazine (in PHP), Eco Consulting (in SSI), and Christian Heilmann (SSI and PHP).

Quite simply, he’s correct in stating that programmatic features need not be added to CSS proper to achieve desired results, but he’s incorrect in his apparent thinking that designers will be able to use these other tools to leverage CSS. Take, for instance, the probably more familiar (though not linked above) notion of using JavaScript to manipulate CSS values.

var x = document.getElementById('SideBar'); // get #SideBar element
var y = document.getElementById('MainColumn'); // get #MainColumn
var z = document.defaultView.getComputedStyle(y, '').getPropertyValue('height'); // get computed height of #MainColumn
x.style.height = ( parseInt(z) / 2 ) + 'px'; // set #SideBar's height 1/2 of #MainColumn's

This is an example of programmatic code that uses variables and expressions. It sets the element with the ID of SideBar to half the pixel height of the element with the ID of MainColumn. It does this by obtaining the MainColumn‘s height (at the time this code runs) and saving it in a variable, then performs some trivial math to half the value and use the result as the pixel height of the SideBar.

Doing this is currently impossible with CSS alone, yet it’s something that clearly belongs with whatever other “presentational” code exists and not in “programmatic” scripts that would otherwise be charged with defining “functionality.” As Matt states, using JavaScript to “script” solutions to CSS’s shortcomings like this is not an acceptable answer.

CSS doesn’t have [basic logic or maths]. Nor is it the job of JavaScript to make up for this lack of abilities. JavaScript is about interaction behaviour, and what we are talking about here is pure display logic. Not interaction logic.

Moreover, the place designers expect to put code like this is, of course, into a CSS style sheet. The way designers expect to put code like this into CSS is by adding delegation features. Requiring designers to learn JavaScript (or any other programming language) to encode such design relationships is nothing short of ridiculous. In what world is that easier for untrained laymen to understand than CSS?

Adding delegation to CSS is worth the effort

One of Bert’s arguments against such additions to CSS is that implementations would become harder to create, and that we’ll (almost certainly) see more bugs.

extending CSS makes implementing more difficult and programs bigger, which leads to fewer implementations and more bugs. That has to be balanced against the usefulness of the extension.

Although I do agree with his statement that an extension’s usefulness has to be balanced against its potential costs, I think something so fundamental to design methodology as delegation greatly overcompensates for the cost of such implementation efforts. Moreover, if I understand Bert correctly and as he also discusses, the majority of implementations that would need to implement such delegation already have relatively complex internal structures to make the implementation effort somewhat easier:

There is no scoping [in proposals that only define global constants]. That means that an implementation needs a symbol table, but no stack. A stack would require a little bit more memory, but mostly it would make implementations more complex. (Although every programmer has, one hopes, learnt to program a symbol table with lexical scope during his training.) Constants in CSS are thus easier than, e.g., XML Namespaces, which are lexically scoped.

It is different for those CSS implementations that provide a CSS Object Model (an API for manipulating a style sheet in memory). Those implementations do need to keep track of scope in some way, because adding or removing a line of the style sheet can make a previously redundant definition become meaningful.

In order to use JavaScript to solve many of the shortcomings of CSS, as huge numbers of professional web developers do routinely, we use the very CSS Object Model whose prior implementation already exists for us to build upon.

CSS delegation doesn’t grow the size of the language

For the sake of argument, let’s simplify our requirement somewhat so that our somewhat contrived example of design intent is to create a relationship between the MainColumn and the SideBar elements such that they are of equal height. This is more informally known as “making columns.”

Here’s what a natural, hypothetical snippet of CSS would look like if the language supported delegation features such that it could encode visual relationships.

#SideBar { height: #MainColumn; }

This code theoretically says almost the exact same thing as the JavaScript shown earlier (save for the division, of course); it takes the computed value of the MainColumn element’s height property and applies that value to the SideBar element’s height property. In other words, “The SideBar’s (element B’s) height is always the same as the MainColumn’s (element A’s).” (Of course, this is a parse error in reality today.)

This extremely trivial example has some remarkably far-reaching implications, and yet there is really nothing radical about its syntax. Making this a reality significantly expands the capabilities of CSS without dramatically increasing the size of the language. This capability would not only beat the pants offCSS tables,” it also potentially obsoletes the arguably misguided efforts of the CSS3 Advanced Layout and Grid Positioning modules, too.

We’ve long since abandoned table layouts because they force us to use presentational markup. That’s still what “CSS tables” force us to do, too. In other words, with display: table, the SideBar needs to be a child of the MainColumn element or, maybe worse and more likely, a child of a semantically meaningless wrapper element.

CSS positioning was introduced with the promise of freeing us from source-order-dependent styling, without which there is no hope of efficiently abstracting presentation away from structure. Moreover, abstracting presentation away from structure is the single most important prerequisite needed to improve document reusability and strengthen the semantic Web. Absolute positioning works, but limitations elsewhere in CSS mean its use is problematic for many designs, so in practice it doesn’t gain widespread adoption.

Here’s a theoretical solution to a two-column and a footer layout using CSS delegation with this semantic HTML:

<body>
    <div id="MainColumn">I'm the main column.</div>
    <div id="SideBar">I'm the right-hand sidebar.</div>
    <div id="Legalese">No one will read me.</div>
</body>

The CSS would look extremely familiar, possibly like this:

#MainColumn { margin: 0 25% 1em 0; float: left; }
#SideBar { width: 25%; min-height: #MainColumn; }

Using the same HTML, the same solution using the CSS3 Advanced Layout module would look something more like this, although to be frank I’m not certain I fully understand this syntax even after staring at it for months:

body {
    display: "a  b"
             ".  ." /1em
             "c  c"
             75% 25%
}
#MainColumn { position: a; }
#SideBar { position: b; }
#Legalese { position: c; }

Not only does there seem to me to be far more indirection in this method than there would be using CSS delegation, there is also an enormous increase to the size of the CSS language: a new (ASCII-art?!) value to the display property whose syntax is clunky at best. A similar story can be said of the CSS3 Grid Positioning module, which does lots more than just add a new (already complex) gr CSS unit.

The upshot is that the Advanced Layout and the Grid Positioning modules are doing some of the right things in many of the wrong ways. Both those modules add unnecessary complexity to CSS without giving designers a natural way to say what they mean. They do more to introduce obfuscation and indirection than simple delegation would, and they aren’t as broadly capable. Both of them try to solve a specific problem instead of dealing with fundamental deficiencies in the toolset designer’s have to work with.

Designers want relationships via delegation, not variables

Adding delegation such as that I’ve just shown is a natural, necessary addition to CSS because it is how designers create visual components—such as grids—in their designs. Variables (and constants, and macros, etc.), which simply reuse and modify pre-defined statements aren’t what designers care about. Adding them will bloat CSS without adding useful functionality.

“Okay,” you may be saying to yourself, “but delegation is itself a kind of variable, isn’t it?” Technically yes, however adding delegation resolves the core deficiency in the CSS language that designers need to use every day. Yes, it’s technically a form of variable, but that’s not how designers think of it. To say that one element’s visual properties is like another makes a variable only by creating a logical and visually appropriate mapping from the first element’s property to the second independent of markup, thereby avoiding indirection in the form of a variable name or other unfamiliar symbol.

Delegation like this doesn’t require the addition of anything other than what already exists in CSS. Class names and ID values are identifiers whose indirection people already have to deal with. Using them for delegation (to reference another element’s style) doesn’t increase the cognitive load any more than using them to reference HTML elements does. Though untested, the cognitive load might actually be even less since the CSS delegation’s references could be in the same (style sheet) file.

Moreover, delegation will increase the likelihood of document reusability by enabling style sheets to be more self-describing, more self-referential, in a similar way as good markup is. It satisfies a very fundamental need that designers have to define graphical relationships between elements. At the same time, it does so in a way that is natural to both their way of thinking and beneficial to the separation of concerns principle on which the “web stack” (the trifecta of HTML, CSS, and JavaScript) is based.

Written by Meitar

December 14th, 2008 at 2:55 am

18 Responses to 'Why CSS needs delegation capabilities and not “variables”'

Subscribe to comments with RSS or TrackBack to 'Why CSS needs delegation capabilities and not “variables”'.

  1. Compelling argument, Meitar. I think I could get some mileage out delegation and it makes perfect sense compared to the alternative model.

    Joe Lewis

    14 Dec 08 at 11:40 AM

  2. [...] of CSS Variables or CSS Constants. Some very respected designer and developers have argued against it, while others have argued for it. I hope, for the sake of a better web, that an effective CSS-only [...]

  3. [...] of CSS Variables or CSS Constants. Some very respected designer and developers have argued against it, while others have argued for it. I hope, for the sake of a better web, that an effective CSS-only [...]

  4. [...] of CSS Variables or CSS Constants. Some very respected designer and developers have argued against it, while others have argued for it. I hope, for the sake of a better web, that an effective CSS-only [...]

  5. [...] of CSS Variables or CSS Constants. Some very respected designer and developers have argued against it, while others have argued for it. I hope, for the sake of a better web, that an effective CSS-only [...]

  6. [...] Vari­ables or CSS Con­stants. Some very respected designer and devel­op­ers have argued against it, while oth­ers have argued for it. I hope, for the sake of a bet­ter web, that an effec­tive [...]

  7. WOW, delegation as you present it would be really great!

    Do you know any project out there that would take this syntax and compile it into a mix of “current” CSS and JS code, as LESS does for variables, etc.?

    Nicolas Hoizey

    26 Aug 09 at 5:21 AM

  8. Sorry, Nicolas, I’m not aware of any tool that uses the syntax for delegation I described above. I remember hearing about LESS a few months ago, but didn’t explore much beyond the home page because of the language-size problem. (LESS CSS’s syntax is a significant departure from standard CSS’s simplicity.)

    Meitar

    27 Aug 09 at 2:22 AM

  9. [...] of CSS Variables or CSS Constants. Some very respected designer and developers have argued against it, while others have argued for it. I hope, for the sake of a better web, that an effective CSS-only [...]

  10. Your blog came up in my search and I’m stricken by what you have written on this subject. I am currently branching out my search and thus cannot contribute further, still, I have bookmarked your website and will be returning to keep up with any upcoming updates. Just love it and thanks for allowing my comment.

    flash hjemmeside

    25 Dec 09 at 3:33 AM

  11. Genius! CSS with delegation and simple math capabilities, like .class {width:(#main-10px);} would basically solve every stubborn issue I have with CSS.

    Chad von Nau

    19 Jul 10 at 4:14 AM

  12. A few remarks:
    First, I don’t see how the need for delegation would obliterate the need for CSS constants. The use cases are quite different. CSS delegation would be the best tool to make sure two elements have the same height, regardless of their individual content and of their position in the DOM (display:table and display:box are both tools you can use for that, but your elements must be siblings and you might need additional markup for raws or box/table containers). But CSS constants would be better suited for declaring and reusing values for color palettes and grids. Using delegation for color palettes would be a hack (works, but wrong tool for the job); using constants for same-height layout would be another one (it wouldn’t work reliably since you would have to give a fixed height, which you should generally avoid).
    So your proposal for CSS delegation should be about replacing getComputedStyle abuse, and not about replacing the need for CSS constants.

    Then, your proposal is awfully limited. From the syntax and examples you give, it looks like you would need to give unique ids to basically every container in the page. I can see a lot of use cases where I would need grid-like behaviour (“I want this set of elements to act as a column, this other set to act as a row with same-height cells, etc.”) but where your proposal wouldn’t help if I don’t have a unique ID for each element. It would be fine for short pages and websites that don’t change much, but for big pages and very changing websites built with many reusable components… that would be a nightmare. I also think the ASCII-art syntax AND use of the display property for grid layout is nonsense, but the scope and power of the feature itself is quite good, and much more interesting for layout than hackish use of CSS delegation. Don’t throw the feature baby with the syntax bathwater. :)

    Finally, you’re suggesting a very broad feature but give only one use case as an example. Why implement such a broad feature (access to any computed value of any element, through CSS, and use for any property of any declaration block…) when the main concern is layout, and maybe only a small subset of layout needs? Sadly, that’s not very convincing.
    You need more compelling use cases before you can convince a majority of CSS coders that a new language feature is needed.
    (That’s true for CSS constants too, obviously.)

    PS: I liked your recap of the CSS variables debate. I think Bert Bos in his insistence on simplicity. He doesn’t seem to realize that CSS is a professional tool too, not exclusively something for hobbyists and graphic designers that occasionally dabble in code. There are webdesigners who are great expert coders, and front-end developers who specialize in HTML, CSS, and JavaScript (+accessibility, front-end performance and related concerns). What’s more, fewer and fewer content creators (in proportion) are using CSS; instead, they use CMS platforms and software. So I’m more in line with what you write: IF the new feature is worth the additional complexity and a good solution to real needs, go for it. It’s not as if the complexity will be forced down the throats of hobbyists and beginners (are they forced to used complex CSS3 gradients? no, they can stick to background images or aim for simpler designs).

    Florent V.

    24 Aug 10 at 8:21 AM

  13. I’m qualify as a developer and I’m confused by what you mean when you say delegation. It makes it harder for me to understand CSS.

    Variables, however, wouldn’t. As they are pretty much the simplest concept in the universe. This delegation thing seems really abstract and hard to hold in your head.

    x, however, everyone learned in algebra somewhere between the ages of 12 and 17. And I was always saying I’d never use it in real life–ok, I don’t, but the concept of a token standing in for an unknown value, at least…

    Plus, CSS keeps adding modules and properties. Has anyone done a proper count of all the properties likely to exist in CSS3? I know many of them are just proposals at this point, but still, several have advanced beyond that. By CSS4 aren’t we talking about a vocabulary of hundreds of properties? Have you seen the syntax of gradients? Talk about something that is hard to hold in your head.

    Basing your arguments on “what other people will be able to understand” is a pretty shaky foundation. You have no clue what other people will understand. Walk up to a designer and say “variables” and, yeah, maybe they’ll be like, “what? that’s programming stuff! scary!” But say, “hey, there are two things I’ve wanted over and over in CSS. one is not having to copy and paste the hex code of a color, the other is the ability to set padding to something like line-height minus font-size. how about you?”

    Casual content authors are perhaps unlikely to have written CSS on such a scale that they’d feel as rousing a need? So perhaps they’d ignore it until they needed and keep on doing things the way they always have….

    Usme Cah

    17 Sep 11 at 2:22 AM

  14. I’m qualify as a developer and I’m confused by what you mean when you say delegation. It makes it harder for me to understand CSS. Variables, however, wouldn’t. As they are pretty much the simplest concept in the universe. This delegation thing seems really abstract and hard to hold in your head.

    In a roundabout way, Usme Cah, I think you’ve proven my point. :) Delegation is functionally equivalent to variabilization but implemented from the perspective of a designer rather than a developer. And perspective coupled with function is the whole point, isn’t it? If we want designers to use CSS, then implementing capability from the perspective of developers and not designers is clearly self-defeating.

    Meitar

    17 Sep 11 at 4:57 PM

Leave a Reply