Title: CSS Custom Properties for Cascading Variables Module Level 1 Status: ED Work Status: Testing Shortname: css-variables Level: 1 Group: csswg TR: https://www.w3.org/TR/css-variables-1/ ED: https://drafts.csswg.org/css-variables/ Previous Version: https://www.w3.org/TR/2015/CR-css-variables-1-20151203/ Previous Version: https://www.w3.org/TR/2014/WD-css-variables-1-20140506/ Previous Version: https://www.w3.org/TR/2013/WD-css-variables-1-20130620/ Previous Version: https://www.w3.org/TR/2013/WD-css-variables-20130312/ Previous Version: https://www.w3.org/TR/2012/WD-css-variables-20120410/ Editor: Tab Atkins Jr., Google, http://xanthir.com/contact, w3cid 42199 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. Default Highlight: css
spec:css-syntax-3; type:dfn; text:identifier
Name: --* Value: <> Initial: (nothing, see prose) Applies to: all elements Inherited: yes Computed value: specified value with variables substituted (but see prose for "invalid variables") Animatable: no
User Agents are expected to support this property on all media, including non-visual ones.
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, except ''--'' itself, which is reserved for future use by CSS. Custom properties are solely for use by authors and users; CSS will never give them a meaning beyond what is presented here.
: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,
:root:lang(en) {--external-link: "external link";}
:root:lang(de) {--external-link: "externer Link";}
a[href^="http"]::after {content: " (" var(--external-link) ")"}
The variable declarations can even be kept in a separate file,
to make maintaining the translations simpler.
: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.)> [, < > ]? )
.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.
/* 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 {
--gap: 20;
margin-top: var(--gap)px;
}
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!!property',
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.
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. Privacy and Security Considerations {#priv-sec} =============================================== This specification defines a purely author-level mechanism for passing styling information around within a page they control. As such, there are no new privacy or security considerations.