!Date: 2014-05-06 Status: ED Shortname: css-variables Level: 1 Group: csswg TR: http://www.w3.org/TR/css-variables-1/ ED: http://dev.w3.org/csswg/css-variables/ Previous Version: http://www.w3.org/TR/2013/WD-css-variables-1-20130620/ Previous Version: http://www.w3.org/TR/2013/WD-css-variables-20130312/ Previous Version: http://www.w3.org/TR/2012/WD-css-variables-20120410/ Editor: Tab Atkins Jr., Google, http://xanthir.com/contact Abstract: This module introduces cascading variables as a new primitive value type that is accepted by all CSS properties, and custom properties for defining them. Ignored Terms: case-insensitive, getpropertyvalue() Link Defaults: css-color-3 (property) color, cssom-1 (interface) cssstyledeclaration
Name: --* Value: <A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS), like '--foo'. The <custom-property-name> production corresponds to this: it's defined as any valid identifier that starts with two dashes. Custom properties are solely for use by authors and users; CSS will never give them a meaning beyond what is presented here.> Initial: (nothing, see prose) Applies to: all elements Inherited: yes Computed value: specified value with variables substituted (but see prose for "invalid variables") Media: all Animatable: no
:root {
--main-color: #06c;
--accent-color: #006;
}
/* The rest of the CSS file */
#foo h1 {
color: var(--main-color);
}
The naming provides a mnemonic for the colors,
prevents difficult-to-spot typos in the color codes,
and if the theme colors are ever changed,
focuses the change on one simple spot
(the custom property value)
rather than requiring many edits across all stylesheets in the webpage.
--foo: if(x > 5) this.width = 10;While this value is obviously useless as a variable, as it would be invalid in any normal property, it might be read and acted on by JavaScript.
style attribute,
can be read or set using the CSSOM, etc.
Notably, they can even be transitioned or animated,
but since the UA has no way to interpret their contents,
they always use the "flips at 50%" behavior
that is used for any other pair of values that can't be intelligently interpolated.
However, any custom property used in a ''@keyframes'' rule
becomes animation-tainted,
which affects how it is treated when referred to via the ''var()'' function in an animation property.
:root {
--header-color: #06c;
}
declares a custom property named '--header-color' on the root element,
and assigns to it the value "#06c".
This property is then inherited to the elements in the rest of the document.
Its value can be referenced with the ''var()'' function:
h1 { background-color: var(--header-color); }
The preceding rule is equivalent to writing ''background-color: #06c;'',
except that the variable name makes the origin of the color clearer,
and if ''var(--header-color)'' is used on other elements in the document,
all of the uses can be updated at once
by changing the '--header-color' property on the root element.
:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
<p>I inherited blue from the root element!</p>
<div>I got green set directly on me!</div>
<div id='alert'>
While I got red set directly on me!
<p>I'm red too, because of inheritance!</p>
</div>
:root {
--main-color: #c06;
--accent-background: linear-gradient(to top, var(--main-color), white);
}
The '--accent-background' property
(along with any other properties that use ''var(--main-color)'')
will automatically update when the '--main-color' property is changed.
:root {
--one: calc(var(--two) + 20px);
--two: calc(var(--one) - 20px);
}
Both '--one' and '--two' now compute to their initial value,
rather than lengths.
<one><two><three /></two></one>
one { --foo: 10px; }
two { --bar: calc(var(--foo) + 10px); }
three { --foo: calc(var(--bar) + 10px); }
The <one> element defines a value for '--foo'.
The <two> element inherits this value,
and additionally assigns a value to '--bar' using the ''foo'' variable.
Finally,
the <three> element inherits the '--bar' value
after variable substitution
(in other words, it sees the value ''calc(10px + 10px)''),
and then redefines '--foo' in terms of that value.
Since the value it inherited for '--bar' no longer contains a reference to the '--foo' property defined on <one>,
defining '--foo' using the ''var(--bar)'' variable is not cyclic,
and actually defines a value that will eventually
(when referenced as a variable in a normal property)
resolve to ''30px''.
var() = var( <The ''var()'' function can be used in place of any part of a value in any property on an element. The ''var()'' function can not be used as property names, selectors, or anything else besides property values. (Doing so usually produces invalid syntax, or else a value whose meaning has no connection to the variable.) The first argument to the function is the name of the custom property to be substituted. The second argument to the function, if provided, is a fallback value, which is used as the substitution value when the referenced custom property is invalid. Note: The syntax of the fallback, like that of custom properties, allows commas. For example, ''var(--foo, red, blue)'' defines a fallback of ''red, blue''; that is, anything between the first comma and the end of the function is considered a fallback value. If a property contains one or more ''var()'' functions, and those functions are syntactically valid, the entire property's grammar must be assumed to be valid at parse time. It is only syntax-checked at computed-value time, after ''var()'' functions have been substituted. To substitute a var() in a property's value:> [, < > ]? )
/* In the component's style: */
.component .header {
color: var(--header-color, blue);
}
.component .text {
color: var(--text-color, black);
}
/* In the larger application's style: */
.component {
--text-color: #080;
/* header-color isn't set,
and so remains blue,
the fallback value */
}
.foo {
--side: margin-top;
var(--side): 20px;
}
This is not equivalent to setting ''margin-top: 20px;''.
Instead, the second declaration is simply thrown away as a syntax error
for having an invalid property name.
Similarly, you can't build up a single token where part of it is provided by a variable:
.foo {
--gap: 20;
margin-top: var(--gap)px;
}
Again, this is not equivalent to setting ''margin-top: 20px;'' (a length).
Instead, it's equivalent to ''margin-top: 20 px;'' (a number followed by an ident),
which is simply an invalid value for the 'margin-top' property.
Note, though, that ''calc()'' can be used to validly achieve the same thing, like so:
.foo {
--gap: 20;
margin-top: calc(var(--gap) * 1px);
}
:root { --looks-valid: 20px; }
p { background-color: var(--looks-valid); }
Since ''20px'' is an invalid value for 'background-color',
this instance of the property computes to ''transparent''
(the initial value for 'background-color')
instead.
If the property was one that's inherited by default,
such as 'color',
it would compute to the inherited value
rather than the initial value.
:root { --not-a-color: 20px; }
p { background-color: red; }
p { background-color: var(--not-a-color); }
the <p> elements will have transparent backgrounds
(the initial value for 'background-color'),
rather than red backgrounds.
The same would happen if the custom property itself was unset,
or contained an invalid ''var()'' function.
Note the difference between this
and what happens if the author had just written ''background-color: 20px'' directly in their stylesheet -
that would be a normal syntax error,
which would cause the rule to be discarded,
so the ''background-color: red'' rule would be used instead.
Ordinarily, property names are restricted to the ASCII range and are case-insensitive, so implementations typically serialize the name lowercased.
Many thanks to several people in the CSS Working Group for keeping the dream of variables alive over the years, particularly Daniel Glazman and David Hyatt. Thanks to multiple people on the mailing list for helping contribute to the development of this incarnation of variables, particularly Brian Kardell, David Baron, François Remy, Roland Steiner, and Shane Stephens.