• 200815 Nov

    There’s been an apparent need (voiced by the web community) for CSS-based Constants ever since the conception of CSS (even though there are many established server-side preprocessors in existance). From reading blogs and the like, people are either very much in favour or very much against the idea, but the feature’s mixed reception hasn’t stopped members of the CSSWG exploring and discussing the idea further, to the point where we now have two fairly detailed proposals from members of the Working Group. The aim of this post is to explore and then summarise the current state of both proposals (from an authors not a vendors point of view), comparing features of both.

    Back in March this year, Dave Hyatt and Daniel Glazman combined forces and presented the first formal proposal for Variables to the Working Group, and (based on this spec) Hyatt subsequently implemented the module into Webkit nightlies; the implementation was distributed for around 5 months, but was later removed due to concerns regarding feature adoption by authors before the spec had any time to mature. In August this year, fantasai submitted a counter-proposal which detailed plans for a parse-time syntax for Constants (which are lost after the variables are parsed and therefore not mutable), compared to Hyatt’s/Glazman’s proposal which allowed for scriptable Variables.

    Types of Constants

    Fantasai’s proposal features three types of named Constants, ‘values’, ‘style-sets’ and ‘selectors’; a value constant represents a property value, a style-set constant represents one or more property declarations and a selector constant represents a selector. Each are declared using an @define rule and as fantasai explains, the syntax of an @define rule is the @define at-keyword, followed by either the values keyword (for declaring value constants) or the style-sets keyword (for declaring style-set constants) or the selectors keyword (for declaring selector constants), followed by a block. Examples (ripped straight from her proposal :)) showing the syntax for each of the three Constants are below:-

    Values

    @define values { textColor: black; bgColor: white; accentColor: silver; accentBorder: double silver 5px; }

    Style-sets

    define style-sets { noteBox { border-style: solid; padding: 1em; border-radius: 1em; } quoteBox { margin: 1em; } }

    A feature of fantasai’s proposal is that constants are re-usable, so you can include ‘style-set templates’ which can be applied to multiple selector declarations, using different value constant values.

    Selectors

    Note that any selectors used in such a variable aren’t allowed to be grouped (using the comma-seperated grouping syntax), since we will have the ability to group selector variables anyway. Selector constants would be useful for repeatedly selecting child/grandchild etc elements deep within a complex DOM tree; consider this:-

    @define selectors { deeplynestedelement: body.home > div#main.container ~ ul#navigation > li a[href="http"] span#child > span#imrunningoutofnames;}
    deeplynestedelement u, deeplynested b{ color:red; }

    And with the addition of a possible :match() pseudo class in Selectors Level 4, you could do something like this to make the above statement even more organised:-

    deeplynestedelement:matches(u,b){ color:red; }

    Instead Hyatt’s/Glazman’s proposal simply utilises a new @variables rule in which any type of variable (presumably) can be used, without the need for type keywords – their proposal isn’t actually clear on whether different types of variables can be parsed (or whether this proposal simply targets value constants), however, after looking at several test cases, the implementation seems like it was capable of at least parsing ‘style-sets’ constants too.

    @variables { CorporateLogoBGColor: #fe8d12; }

    div.logoContainer { background-color: var(CorporateLogoBGColor); }

    Scoping

    Two fairly major differences between the two proposals are their scoping behaviour. In fantasai’s proposal, by default, the scope of a named constant does not ordinarily cross @import boundaries; this essentially means that the use of variables declared in one @import are restricted to that particular stylesheet, unlike Hyatt’s/Glazman’s proposal where, by default, constants cross @import boundaries. However, using fantasai’s proposal, authors do have complete control over the scope by using one of three new keywords (which is placed between the @import keyword and the stylesheet URI), push, pull and sync; pull allows constants declared within the imported stylesheet to be used in the importing stylesheet; push allows constants declared above the @import rule in the importing style sheet to be used the imported style sheet; sync allows both of the previous, simultaneously.

    The two proposals differ also in the way that constants relate to, and work with Media Types. In Hyatt’s/Glazman’s proposal, an optional Media Type keyword can be placed between the @variables keyword and succeeding block declaration. In fantasais proposal, constant declarations (placed within a @define block) can be nested within an @media block. However she metions, …if declared inside an @media rule, the scope of the declaration does not end with the @media block, meaning that constants can be used outside of the @media they’re placed in. It’s worth mentioning that the @media rule model/syntax differences could be trivially modified to use the other’s media type syntax.

    You can skip to the end and leave a response.


  • Comments

    • 01.

      My humble opinion is that 95% of websites will never need CSS constants/variables, and the remaining 5% are made by web developers who should have the skills to implement it using one of the alternative methods mentioned above and in Bert Bos’ article. I’m sorry but if you really need CSS constants/variables in your project, you’re doing it wrong. Proper CSS for big projects is all about modularity, and combining several classes with small sets of properties.

      Do the test for yourself and see if you can read and understand these code examples above without looking at the descriptions. I don’t see the point in adding this extra layer of complexity to CSS. If implementing new modules in CSS was painless and swift, I’d have no obligations at all. But we all know some the kids in class are having a very hard time keeping up. This will only burden them more.

    • 02.

       @Lensco: Combining small classes with few properties, usually breaks the separation of content and presenatation. For instance, a class “rounded” would be obsolete if you stop using rounded corners, so you would have to change the markup. Now consider the case that you could have a style-set about rounded corners and add it to each relevant class. No bloated markup, no presentational classes, easily maintainable css.

    • 03.

      You do know you can have more than one selector for each collection of properties right?

      .myclass > .myotherclass,
      #thisbeid, p, body,
      #content > h1 {
      border: 10px solid red;
      border-radius: 1em;
      }

      Much simpler and much easier to see what gets affected if you, for example, change the color of the border. Also, there’s even less bloat \o/

      BTW @staff, the text in this textbox hurts my eyes, it’s small and the contrast is really bad too.

    • 04.

      I honestly can’t see many valid uses for variables, I’m sure they’d be useful if used well, but there are many negative aspects…

      * Other CSS3 features will reduce the need for repetitive code, see border-radius, multiple backgrounds, etc…
      * CSS doesn’t require much code reuse in the first place.
      * Variables could add an extra layer of confusion for learners.
      * Obfuscation (harder to see exactly what the CSS is doing).

      Benefits:
      * No need to memorize hex and RGB values, but you still have to remember the associated variable names.
      * Less repetitive typing.
      * May reduce the possibility of typos and inconsistent code.

      Variables have their place in CSS, but I’ll be happy without them.

      @Lea: I’m not sure what that has to do with variables.

    • 05.

      I’m definitely in favour of introducing variables, and I lean towards the Hyatt/Glazman suggestion, purely because it is the more simple solution – albeit not as flexible as fantasai’s.

      To anyone who thinks that this makes CSS too difficult to learn: I disagree. Yes, it makes it more complex but – crucially – you don’t need to learn this in order to use CSS to the same degree we use it today; you can still build great styles without CSS variables, but with them it becomes easier.

    • 06.

       I think these proposals are amazing. Imagine them together with other 2 proposals would mean image slicing kiss of death. I mean you create an image template for the site and you don’t have to slice it. You only define the rectangular sections from the template image and they will act as sliced images in your site. Can you imagine how flexible will be to create a site from a template. And how easy will be to make the modifications(to change the dimensions of a slice if your slicing went wrong).
      My proposal would be to exist a new kind of variable – image variable defined as follows:

      @define imag-vars{ imagevar1 { rect(20,30,40,50) url(http://www.example.com/images.image.jpg)} , imagevar2 { rect(60,70,80,90) url(http://www.example.com/images.image.jpg)}}

      where rect(60,70,80,90) is the square that defines the image on the sprite (sprite – an image that contains a group of images)

      after that we can apply the slice of the image as follows:

      background-image:var(imagevar1);

      is instead of the proposal to add background-image-crop to css3(i mean to exist a modality to crop images for background as well, similarly to clip:rect() property )

    • 07.

      @Lea Verou: If you don’t call that class ’rounded’ the whole problem is solved right? Also, it’s about time we leave behind the myth of 100% seperated content and presentation. CSS Zen Garden was a cool experiment, but it was exactly that, a lab experiment. No redesign ever happens without touching any HTML. Powerful site-wide adjustments are often but a find & replace away.

      @Peter Gasston: as I said, I’m not so much worried by complexity or having to learn something new, rather than the delay this will bring upon implementation of other — more important — parts of CSS.

      I’m not exactly against, I’d only give it a very low priority.

    • 08.

      [...] on the table, but I’m not really in favor of the idea in general. Here’s what I wrote: My humble opinion is that 95% of websites will never need CSS constants/variables, and the [...]

    • 09.

      Well CSS3 is modular, so it’s not as if one new feature will delay the whole thing. As we’re seeing with the Transformations module, what we need to make the whole thing move faster is for a couple of browser makers to implement it – with browser prefixes – so that it can be experimented with and any shortcomings found.

    • 10.

      I’m normally a happy lurker but my side is losing… I think variables will be a great addition to CSS!

      My reasons:

      - a colour scheme for a website often consists of a handful of hex codes used in a variety of ways. It would be nice to refer to these as variables instead of hexes so if they need to be adjusted you can do it in one place. This will be especially cool when we can change colour schemes for different sections of sites by only changing the variables.

      - when I have a number of elements with a common style, for example horizontal navigation menus, it’s not semantic or maintainable to apply the class to them all (for example “horizonalnav”), but listing them all together in the style sheet becomes a maintenance nightmare too because it separates them from the rest of the styles applied to the menu. Both of these are a matter of cleaner smaller CSS.

      The beauty of CSS variables is… if you don’t like them, you don’t have to use them ;)

    • 11.

      Stephanie’s comment is exactly why constants would be great. I’ve run in to these situations countless times and there is no CSS-only solution.

    • 12.

      I definately agree with Stephanie. When I create a stylesheet for a project it usually ends up with a comment block at the top saying what each of a number of color codes are for. Using variable names would make it much easier.

      Also, grouping common styles via variables would be much cleaner, in my eyes. Yes, you can define a number of selectors for a given block, but I tend to end up with several blocks for any given selector, often spread all over the place. Variables would make this much easier, especially if I could do something like:

      div.pullquote {
      quoteBox;
      pointer;
      }

      where I’d also use quoteBox for other types of quotes and pointer for other types of call outs. It could definately make things much more readable.

      Whether having these variables mutable over the life of the stylesheet is useful is questionable, however.

      Of course, I’m a programmer, so I like variables. :)

    • 13.

      The only thing I need personally is better color theme handling across style sheets.
      How about very simple proposal for color constants:
      @constants {
      Attention: Red;
      Search: #666;
      MainBg: #C873C8;
      }
      ….
      div.search p { background: Search }
      ….
      div.search2 div { border-color: MainBg }
      ….
      p.attention { color: Attention, border: 2px solid Attention }

      Scoping can be ruled out also in pretty simple way:
      If @constants rule (which I suppose should be only one for stylesheet, and placed only on very start of document) placed after @import rule then it should be not applied for this imported stylesheet.
      If @constants rule comes before @import, then all constants are availabe for imported stylesheet, but can be overwritten by imported stylesheet’s @constants rule.

    • 14.

      I completely support the new css variables proposals. Having created very large and complex stylesheets, some which are well over a 1000 lines this would make my life a lot easier. It’s also wasteful to have to keep repeating selectors just so that you reference the color in one area of your stylesheet. This is especially annoying if you have really long selectors that would need to be repeated over and over and over again. It would be much shorter and more manageable to just plop in a short variable instead.

    • 15.
    • 16.

      I worked at a major web services company where I defined and implemented very simple variables support in CSS (CSSX – patent pending). The task at hand was to implement a themeing system that could apply the same theme across a bunch of different sites and yet has very small learning curve for CSS authors. The solution was instantly liked and adopted by everyone who saw it and we found out many other advantages other than the intended themeing use. Of course we had to preprocess it into CSS before sending to browsers, but it would be great if something similar is available in browsers through the CSS 3 standard. Here is our syntax -

      #define {TextColor1: #444; TextColor2: #777; TextColorBold: #111}
      .MyBox {color: ?TextColor1}
      .MyBox .ImportantStuff {color: ?TextColorBold}
      .AnotherBox {inherit: MyBox; color: ?TextColor2}

      This is equivalent to the following CSS -
      .MyBox {color: #444}
      .MyBox .ImportantStuff {color: #111}
      .AnotherBox {color:#444; color: #777}
      .AnotherBox .ImportantStuff {color: #111}

      You will notice that the variables are simple macro-like substitutes and the “inherit: ClassName” syntax will bring in all attributes of the class along with any other rules that include that class. Small side effect – “#define” is taken so can’t use “define” as an html id.

      More complex syntax could add more power, but this simple syntax was more than enough to meet the requirements we had.

      Why do this in browser?
      - Using the inherit syntax keeps CSS files smaller, processing on the server side ‘unfolds’ the inherits and we have larger files to send to the browser.
      - Also if only some variables need to be changed (e.g. switching a theme) we could send a new CSS file down with a simple #define block with new variable values, rather than sending whole CSS down preprocessed with the new values.

    • 17.

      I know it’s been said before, but I can’t help but continue to wonder

      Why doesn’t CSS just adopt XPath for selectors?

      - Easy to learn
      - Most CSS selectors have direct equivalents in XPath, making learning and conversion easy
      - XPath includes many powerful features for advanced users

      It wouldn’t exactly solve the constants debate, but it would make selectors powerful enough that the CSS authors who want to turn it into a programming language might at least feel that they have enough power with XPath that they might be willing to live without constants.

    • 18.

      But why add this?
      Who needs image sprites with http://en.wikipedia.org/wiki/Data_URI_scheme supported?

    • 19.

      I don’t think CSS needs variables (mutable???) or even constants – especially in such cumbersome form as in these proposals.

      All that CSS really needs is just a rule concatenation mechanism (inside stylesheet). It would give a way more possibilities without introducing any new entities.

      Say, one could simply define a regular rule:

      .myTextColor{color:#000}

      .roundCorners{border-radius:4px;}

      and refer to it from other rules:

      .myPage {background:pink}.myColor.roundCorners

      And those rules would combine exactly the same way as if these styles were specified in html as:

    • 20.

       I have a header div and a left div. The header div is absolute-positioned in relation to the top of the page. I want the left div (and the main div) to drop the height of the top div. Therefore I’d like to use a CSS variable, so that the header div height can be changed without needing going through my CSS every time and doing multiple replaces. Anyone wants to tell me that I ad doing things the wrong way?

    • 21.

      We should not stop the progress. CSS constants atleast are necessity for better style management. Yes, its possible to name a class as red and give it its own red colorish rgb style and then add multiple classes to element which would work similarly to constants. It would though lead back to adding styles to html page and not really to css file. Only difference would be that the style attributes have been moved to under class attribute. It would clutter the html.

      Having some constants would make nobodys work harder but make it easier for many.

    • 22.

       I personally prefer the second option. It feels more like c macros to me. The only thing I would change is instead of var(blah), I would prefer $blah. I think this is easier to read and probably easier to parse.

    • 23.

      @Andrey Petrov: I think you have a good idea about scoping. Perhaps something along the following lines:

      @local {
      $color1: #ccc;
      $color2: #999;
      }

      @global {
      $color1: green;
      $color3: red;
      }

      Constants defined in @local would only have scope within the current file. Constants defined in @global would have scope in all stylesheets included in a web page.

    • 24.

      I think this is a great proposal, my preference being with fantasai’s approach (for flexiblity).

      The abstraction is more likely to increase readability and comprehension.

      Given that many styles (box-shadow, gradient backgrounds etc.) require multiple rules to render them reliably across browsers, we get faced with either repeating the same multiple rules for each selector that uses them (bloated & hard to maintain), adding additional mark-up (not a best practise and not always possible), or grouping all applicable selectors (less readable & loses context from other rules).

      For those among us who don’t want the complexity (simplicity?) of learning to use constants/variables, then don’t use them. If it all gets a bit too much perhaps consider flipping burgers. I hear mctrolls are hiring.

      I think it would be great to be able to write css like so.

      @define style-sets { shadow: {…}, gradient: {..} }

      nav { `shadow; `gradient; }
      aside { `shadow }

      Presumably “values” can be used in style-sets too?

    • 25.

      [...] nos alegraríamos mucho de saber que CSS pueda agregar capacidades similares. A pesar de que gran parte de la comunidad esté en desacuerdo (¡Gracias, AM!), yo creo que serían útiles, por varias razones. (Invito a discutir a quién [...]

    • 26.

      Is the CSS constants proposal still planned for a future CSS standards or is this a dead proposal? I’m looking for a way to implement CSS constants, but would like it too be as much standard as possible.

    • 27.

      What if you want to make custom “themes”? Perhaps having separate files for themes and usages would be simpler and lighter. Constants would be defined in a file (which anybody could change for another “configuration”) and implemented in another file (which would not be changed).

      Constants are ALWAYS useful. Saying the opposite is THE SAME as saying that a #define in C is not useful (YES, it’s the same, since those constants or macros are just text replacement and would serve for the same purpose).

Hosting by: