Hacker News new | past | comments | ask | show | jobs | submit login
CSS Variables land in WebKit (webkit.org)
119 points by cleverjake on June 13, 2012 | hide | past | favorite | 65 comments



My issue with the spec the W3C settled on is that it contains nuances that mean it must be implemented in the browser. It is not possible to write a serverside preprocessor that implements the spec.

Unlike other technologies like canvas or AJAX where we've been able to create polyfills for older browsers, authors will now have to make an explicit decision between either using CSS variables or supporting all browsers.


I will make the opposite argument: had they specified something that was no better than what could have been built on the server in pre-processing, they should simply have not bothered.

As we already have servers, and we even already have preprocessors, it provides no benefit to having it in the client to just bake that in. The result isn't even much less efficient: the variable is not going to be that much smaller than the value itself pasted in.

When you combine the want to support popular older browsers, the fact that not everyone will implement it at all, and the assured compatibility issues between implementations, we will just be running the preprocessor anyway and using it for every browser (again: as there is almost no benefit to using the native implementation). By the time we aren't, there will be some other feature we really want the preprocessor for.

However, being able to have variables in media queries does provide drastically different capabilities as a compile target for our preprocessors. To simulate having variables in media queries requires preprocessors to fork entire rules with each of the different possible media query expansions for the variable. This is an actual (albeit not gigantic) benefit that will allow users to download smaller CSS files if the server detects they can handle it.

Therefore, I would look at this more like a CPU that added a new instruction that cannot be implemented as a macro-expansion in an assembler, but for compilers of high-level languages that are capable of detecting support for it, allows much faster or smaller execution when available.


You can't write a server-side implementation of canvas or AJAX either. ^_^ It is possible to create a polyfill for CSS variables if you use JS as well. You can do a mostly-working one relatively easily that covers the simple, static case (where vars aren't changed dynamically), but a feature-complete one is a lot harder.

More directly, though, things that can be done by a preprocessor are, by their very nature, less attractive for us to work on. Syntax improvements are nice, and can justify their existence in the core language, but more important to us in the CSSWG is adding functionality that can't be achieved any other way, or not without a lot of painful hacking.

I'd rather let a thousand flowers bloom on the syntax side while I spend my limited time adding new features.


Can you give some examples of things that can't be done by a preprocessor?


Variable values can cascade like other CSS properties. So, you could define a theme via a set of variables, and redefine those variables in a CSS class ("selected items look like this"), or a media query ("mobile uses this theme"), or via JavaScript. That requires evaluation in the browser.


Preprocessors evaluate CSS and the cascade so there's nothing stopping them from adding local scope or specificity to variables. On the other hand, if you can really edit variable values with Javascript then that would be client-side only, although I haven't seen anything that says you _can_ do that - for all we know Javascript may only allow getting/setting of the evaluated value, not the variable expression itself.


> Preprocessors evaluate CSS and the cascade so there's nothing stopping them from adding local scope or specificity to variables.

That cascade depends on the structure of the document, not just the CSS. For instance, consider the following (contrived) example:

    :root { var-accent: black; }
    .someclass > :first-child { var-accent: blue; }
    .otherclass { background-color: var(accent); }
    .anotherclass :first-letter { color: var(accent); }
The value of var(accent) for any element depends on whether the ancestors of that element include the first child of an element with class="someclass". For a preprocessor to duplicate that effect on the server side, it would need to construct all possible combinations of the selectors for the variables and the selectors depending on those variables:

    .otherclass { background-color: black; }
    .anotherclass :first-letter { color: black; }
    .someclass > :first-child .otherclass { background-color: blue; }
    .someclass > :first-child .anotherclass :first-letter { color: blue; }
Now consider that with a dozen variables and a hundred variable-dependent rules.

> On the other hand, if you can really edit variable values with Javascript then that would be client-side only, although I haven't seen anything that says you _can_ do that - for all we know Javascript may only allow getting/setting of the evaluated value, not the variable expression itself.

The CSS Variables spec talks about dynamic variable updates via scripting.


A simple example:

   div { var-color: red; }
   p { var-color: blue; }
   section a { color: var(color); }
It is not possible to generate a non-variable version of the CSS without either knowing the structure of the DOM or generating every permutation of selectors (you can imagine how unwieldy this could get). Even if you manage to do this you're changing the specificity of the rules.


While you can't use a server-side preprocessor to implement this, I don't see any fundamental reason why a JavaScript polyfill couldn't implement it on the client side.


I recently discovered Less (https://lesscss.org/), a CSS preprocessor that adds support for variables and many other features, like nested rules and mixins.

Using Less has been one of the most profound upgrades in my use of programming techniques in quite a while. Hopefully browsers will eventually support even more Less-like features.


If you like Less, you should try Sass/SCSS (https://sass-lang.com/) - same idea, but a little more powerful. Here's a good head-to-head: https://css-tricks.com/sass-vs-less/


Since we're listing alternatives, I prefer Stylus (https://github.com/learnboost/stylus).


I look a look at the sass-vs-less link, and I really don't see the draw of either. I don't want a turing-complete language in my css. Simple variable expansion will suffice--basically just syntactic sugar. I don't want yet another game of "find the definition" buried under a hierarchy of indirection. Perhaps its a lack of imagination on my part, but I can't think of a good use of this power for the purposes of styling a document.


I completely agree with you. That said, you can restrict your usage of these things. On the project I'm currently working on, we're only using three features:

1. constants (mostly for colors and a few sizes)

2. mixins/functions/macros for not-completely-standard properties (e.g. gradients, shadows), makes it easier to not forget a prefixed version, easier to update the definition when needed and much, much easier to read

3. nesting and continuations, especially for styling various states of e.g. a link (having to copy/paste a given selector 4 times and change the pseudo-class is no fun).

Still requires some care though, overusing e.g. nesting can mean you find yourself with fucked up huge selectors in the final file.


LESS/Sass completely changes the speed it takes to write things out, cleans up the organizational composition and increases the readability of the file. While I use variables in it (and love it), that isn't the primary reason I do so. You don't play "find-the-definition" when you put all of your mixins as an index at the top.


>I look a look at the sass-vs-less link, and I really don't see the draw of either.

Don't look at them, use then, and you'll see.

>I don't want a turing-complete language in my css. Simple variable expansion will suffice--basically just syntactic sugar.

And they are mostly that --simple variable expansion. But arithmetic is also handy, e.g

.sidebar { width: @page_width - @content_width }

That said, they are not turing-complete as far as I know.

>I don't want yet another game of "find the definition" buried under a hierarchy of indirection.

You never get that. You only have to look at the LESS or SASS file, never the generated CSS.

And you can mentally map what you see in the browser's CSS inspector with the relevant LESS/SASS rule trivially.

It's nothing like Coffeescript in this regard, where you (sometimes) have to hunt to see the original error.


I appreciate the response. I'll have to give them an honest try before making a judgement.


I've yet to get into Less or SASS/SCSS because I'm still happy using a template engine (in my case Template::Toolkit) to manage my CSS.

They do look nice but currently I still prefer not to blur the edges of what is or isn't CSS.


I would welcome this if I hadn't finally just gotten on board the SASS train. All I see this doing (for some ill-defined span known as "the present"), is adding another layer of headache into the browser compatibility game. Furthermore, I agree with VMG that there's something to be desired in the chosen syntax.


There's more to it than what Sass, Less and co. can provide. It simplifies dynamically changing a bunch of CSS properties from JavaScript a lot. Instead of changing all the elements using a particular style, you could now change just the variable instead. This gets even more interesting when properties are composed of variables, like gradient colors.

Also, this is a pretty high-level addition. I wouldn't be surprised if someone came up with a polyfill for this soon.


That's the biggest draw that I currently see. I would love to reference other features that SASS and LESS still bring to the table, but the idea of JavaScript fiddling with CSS variables is mouth-watering indeed.


To me it seems a logical progression would be for webkit to include SASS/LESS in the tool chain, instead of trying to re-invent the wheel.

Possibly some sort of solution where the browser receives SASS/LESS files and compiles them into CSS on the fly?


I can imagine you could create one stylesheet for browsers that support CSS variables, and one for browser that don't.


Wouldn't that 'headache' be prevented with SASS until it is supported across the board?


Oh definitely. I just mean to express that I'm not as excited as I otherwise would be. I'm not fortunate enough to be working on the types of projects where that can say to our market "You can take your IE7 and hit the road!" Thus while I wouldn't have been using these variables anyway, I would still have been very excited.


from https://www.w3.org/TR/css-variables/

    :root {
      var-header-color: #06c;
    }
    
    h1 { background-color: var(header-color); }
looks slightly hacky, but better than nothing at all I suppose...


It's nowhere near as nice as the sass/scss/less syntax for css variables.


It's not the css we wanted, it's the css we deserved. :)

But seriously, this is extremely consistant with other css directives. Yes, I'm still going to just use less / stylus / whatever, but browser based vars mean some interesting possibilities sans js.


You can compile your LESS so that no JS is required in the browser.


Yeah but then you can't do wild changes on the fly to vars, which was what I was alluding to.


This looks like crap, I am sticking to LESS. It's not worth standardizing half assed stuff like this. These standards groups should open their eyes and look around before standardizing something.


It might be of use in CSS debugging, not that I have a huge problem debugging LESS files. But eventually perhaps there will be LESS -> CSS/variables we can test with.


Seriously? Debugging in Sass is a no-brainer - it barfs as soon as there's an error and it's blatantly obvious as soon as you load the page, since the relevant errors are splattered all over the the top of the page (this is a good thing).

This proposal by the W3C is definitely not-even-half-baked.


I don't mean debugging in the sense of "there's a compilation error", I mean in the sense of "oh, that box has a blue border? That's wrong- what line did I define that variable on?". As I said, it's not a huge problem right now, but in more complex files it can take time to track down the original definition that led to the CSS you're seeing.


Syntax isn't frozen. Here's another possibility:

:root { $header-color: #06c; } h1 { background-color: $header-color; }

(Note that the spec's use of the :root pseudo is just to generically declare "global" variables that should apply to the whole page. If you're just using HTML, feel free to use "html" or "body" as the selector instead.)


This syntax is clearly preferable, but I think you knew that or you wouldn't have written it :)

I'm guessing the justification for the existence of the awkward var(varname) version is so that you can also have the parent-var(varname) notation.

I do think it's interesting how variables are scoped to dom nodes. Is there any reason it cannot be optional though, so if you omit it, it defaults to global?

$header-color: #06c; h1 { background-color: $header-color; }

I'm guessing the argument against, is that this requires too much of a change to CSS parsers, as it doesn't follow the standard form of <selector> { <properties> }. If that's really the reason it seems a bit of a shame though :/


I disagree that it is preferable, but that is debatable. I say that in part for the reasons you mention, but also because it seems to me that quite a lot of people think that "$header-color" means "substitute the value of the header-color variable here" regardless of which side it is on. I think there is probably a happy middle ground where you achieve all of the goodness (looks like CSS, follows existing core grammar, shows the property nature, uses $ in familiar ways, etc). Not sure what it is, but probably something like:

:root{ def-primarycolor: blue; }

.x{ background-color: $primarycolor; }


Out of curiosity, why was the syntax in the current draft chosen over this?


To be very clear rhe one on the left defines, the one on the right uses.


Oh jeez, that's going to be really cumbersome to write.

edit: I think I'll stick to PHP variables in my CSS for now:

  <?=$color1?>


This is a terrible idea. Do you cachebust your CSS?


I generally make heavy use of both server-side and client-side caching. It really depends on the site. If it's just an internal company tool then I usually don't worry about intelligent caching.

I understand the danger of introducing PHP to CSS though. I won't be making database calls or anything like that from a .css file.


You do lose the benefit of caching with that approach, though.


You don't have to. You treat it like you would with LESS - executes during development and you compile it for production


At that point you should just be using LESS/SASS/etc, though, for the other niceties they provide for working with colors and such.


CSS variables do something fundamentally different than SASS/LESS approaches. Moreover, it is something which those approaches are incapable of doing. Conversely, SASS and LESS do something that CSS can never do - be processed only once.

Much of the confusion I think is in the fact that we are referring to two dramatically different things by the same word "variables". In CSS terms it is more helpful (IMO) to think of them more like "user defined properties" which work exactly like every other property in CSS.


Or call what SASS and LESS do global constants.


Yes, I agree, but too late for that change probably. Plus I'm sure someone will point out that they are not actually necessarily constant by strict definition either. An easier way to think about it is that they are essentially clever compile time template systems which output CSS... It's totally unrelated that their input also happens to look a lot like CSS - it isn't.


Honestly, it seems the server-side solutions for css meta-syntax that supports variables are still more suited for this type of thing (such as SASS).


An interesting feature is dynamic updating of dependent variable properties:

  This example shows a variable property safely using a variable:
  
  :root {
  	var-main-color: #c06;
  	var-accent-background: linear-gradient(to top, var(main-color), white);
  }
  
  The ‘var-accent-background’ property will automatically
  update when the ‘var-main-color’ property is changed.
edit: clarified the wording of this comment to remove ambiguity (not a question).


Trivially, the difference is that neither SASS nor LESS is actually CSS and therefore must be transformed into valid CSS prior to being parsed by the browser. This would eliminate that step.

EDIT: parent originally asked about the difference between this and SASS/LESS.


It wont need to be compiled into CSS—it _is_ CSS?

> EDIT: parent originally asked about the difference between this and SASS/LESS.


I really worry about the future of CSS. It already is the most difficult of all web techniques to use. Once they introduce the css scripting thing all bets are off...


Any idea on when we can expect to see this implemented in Chrome or Safari?


within a couple days on chrome canary. It was in r120154, and the current OS X canary is at r120017. That little of a difference usually means a couple days at most.

Safari on the other hand...probably a year or so. Possibly what comes after mountain lion. They won't add it in until it is fairly stable.


Apple also has WebKit Nightly Builds where it might appear sooner: https://nightly.webkit.org/


Right now it's behind a compile-time flag and although I've asked to go on a runtime flag, we haven't seen that change yet. So.. it won't be available in canary for a few weeks.


Very nice. I cant wait to use this feature.

Putting color codes in one variable will help a lot.


Only problem is that no one else supports it.


Many of the most exciting upcoming features in CSS don't gracefully degrade well. Variables are one, yes, but the same is true of Flexbox or Grid Layout, Regions, and others.

One thing that will help (once it's supported, heh) is the @supports rule https://dev.w3.org/csswg/css3-conditional/#at-supports . (Actually, it'll help even before it's supported, since you can put the "down-level" version outside the rule and then reverse the properties and do the new stuff inside the rule. The inner bits will be completely ignored in old browsers.)


You have to start somewhere. The only real question is whether it can be added as a polyfill on browsers as they catch up.


Nobody supports it yet and it's already done better using preprocessors like Sass. Your move, Sherlock.


I like the part where people get so attached to a tool that they've learned that they reject change. Like your message. Comparing a preprocessor to a native element is asinine. Do you argue against JavaScript features because, given that it's a turing complete language, such things could simply be done with preprocessors?

Seriously the boorish comments about "no support yet" are like listening to fat client advocates in the 90s.


It's not so much about attachment to current tools. It's just that you look at something like this, with all its cumbersome syntax, and wonder why they had to make it so ridiculous. And it's not like nobody had any decent ideas of how to do a nice, simple, clean syntax for variables. In the end I suppose we'll be able to continue using preprocessors, and maybe they can generate the clumsy native CSS variables, so it won't really matter and we'll get the best of both worlds. But it sure would be nice if they wouldn't create new features that instantly feel cumbersome to use compared to what people have already been using.


Agreed, we are embedding chromium in our desktop apps. Here we can depend fully on the features this particular browser version supports.

Cross browser support is not always necessary.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: