Status: ED Shortname: css-variables TR: http://www.w3.org/TR/css-variables/ ED: http://dev.w3.org/csswg/css-variables/ 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.
:root {
var-main-color: #06c;
var-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.
Custom properties can contain a trailing ''!important'', but this is automatically removed from the property's value by the CSS parser, and makes the custom property "important" in the CSS cascade.
var-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.
:root {
var-header-color: #06c;
}
declares a custom property named "var-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 via the "header-color" variable:
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 'var-header-color' property on the root element.
style attribute,
can be read or set using the CSSOM, etc..
:root { var-color: blue; }
div { var-color: green; }
#alert { var-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 {
var-main-color: #c06;
var-accent-background: linear-gradient(to top, var(main-color), white);
}
The 'var-accent-background' property
(along with any other properties that use ''var(main-color)'')
will automatically update when the 'var-main-color' property is changed.
:root {
var-one: calc(var(two) + 20px);
var-two: calc(var(one) - 20px);
}
Both 'var-one' and 'var-two' now define invalid variables rather than lengths.
<one><two><three /></two></one>
one { var-foo: 10px; }
two { var-bar: calc(var(foo) + 10px); }
three { var-foo: calc(var(bar) + 10px); }
The <one> element defines a value for 'var-foo'.
The <two> element inherits this value,
and additionally assigns a value to 'var-bar' using the ''foo'' variable.
Finally,
the <three> element inherits the 'var-bar' value
after variable substitution
(in other words, it sees the value ''calc(10px + 10px)''),
and then redefines 'var-foo' in terms of that value.
Since the value it inherited for 'var-bar' no longer contains a reference to the 'var-foo' property defined on <one>,
defining 'var-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''.
<variable> = var( variable-name [, <A variable can be used in place of any part of a value in any property on an element. Variables 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 <> ]? ) <fallback> = [ < > | < > | < > ]+
/* 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 {
var-text-color: #080;
/* header-color isn't set,
and so remains blue,
the fallback value */
}
.foo {
var-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 {
var-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 {
var-gap: 20;
margin-top: calc(var(gap) * 1px);
}
:root { var-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 { var-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 variable itself was invalid.
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.
CSSStyleDeclaration InterfaceCSSStyleDeclaration interface is amended as follows:
partial interface CSSStyleDeclaration {
readonly attribute CSSVariablesDeclaration var;
}
A CSSStyleDeclaration is the associated style declaration
for the CSSVariablesDeclaration assigned to its var attribute.
While the CSSStyleDeclaration interface normally contains attributes that are camel-cased name variants of all CSS properties
(and sometimes also attributes for their canonical names),
it must not contain any such attributes for custom properties.
The camel-case trick does not work,
as custom property names are case-sensitive,
and there are potentially an infinity of custom properties,
which is incompatible with the normal behavior of exposing every property
whether it was set in the corresponding declaration block or not.
Ordinarily, property names are restricted to the ASCII range and are case-insensitive, so implementations typically serialize the name lowercased.
CSSVariablesDeclaration InterfaceCSSVariablesDeclaration interface
exposes the custom properties declared in the parent declaration block
that have a non-initial value.
interface CSSVariablesDeclaration {
getter DOMString (DOMString varName);
setter creator void (DOMString varName, DOMString varValue);
deleter void (DOMString varName);
}
The supported property names
on a CSSStyleDeclaration object
are the property names of all the custom properties in the CSS declaration block declarations
with a non-initial value,
with the "var-" prefix removed.
Before running any of the algorithms in this section,
prepend "var-" to varName's value.
When asked to get the value of a variable,
if varName is in the CSS declaration block declarations,
invoke getPropertyValue() on the associated style declaration by passing varName as its argument,
and return the returned value.
Otherwise, return the empty string.
When asked to set or create the value of a variable,
invoke setProperty() on the associated style declaration by passing varName as the first argument and varValue as the second argument.
Note that using setProperty() to set a property to the empty string
instead deletes the property.
When asked to delete the value of a variable,
if varName matches the grammar of a custom property name,
invoke removeProperty() on the associated style declaration by passing varName as its argument,
and return the returned value.
Otherwise, do nothing and return the empty string.
div {
var-foo: 16px;
var-Bar: red;
var-foo-bar: 50%;
}
Here are the results of several JavaScript expressions,
assuming that el is a JavaScript variable
holding an element that the above style rule applies to:
| Code | Value | Notes |
|---|---|---|
el.style.var.foo
| "16px"
| The value of 'var-foo'. |
el.style.var.Bar
| "red"
| The value of 'var-Bar'. |
el.style.var["foo-bar"]
| "50%"
| The value of 'var-foo-bar'. |
el.style.varFoo
| n/a | Custom properties don't exist directly on "style" |
el.style.varBar
| n/a | Not even if the casing matches. |
el.style.var.foo-bar
| NaN
| Retrieves the value of 'var-foo'
(the string "16px")
and subtracts some unrelated JavaScript variable named "bar" from it,
rather than just retrieving the value of 'var-foo-bar'.
|
var property:
var customProps = el.style.var;
for(customPropName in customProps) {
if( knownCustomPropName(customPropName) ) {
var customPropValue = customProps[customPropName];
/* Processing code here. */
}
}
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.