This slide deck was created for use in a controlled environment, during a talk. It works best with Chrome. It may or may not work properly in other browsers. The demos were live coded, so these slides are a bit pointless if you never watched the talk.

CSS (Variable) Secrets

By Lea Verou (@LeaVerou)

--color, --corner, inline style, fallback

CSS is awesome

CSS Variables work like
normal CSS properties

inheritance, cancel inheritance, inherit keyword

CSS Variables are
inherited properties
but you can change that

No CSS variables support
No --accent-color set
--accent-color: yellowgreen
--accent-color: 42deg

			background: red;
			background: var(--accent-color, orange);

Invalid at computed-value time = initial

Won’t someone, please, think of browser support?!

Chrome Firefox Edge Safari
CSS Variables 49 31 9.1

Chrome Firefox Edge Safari
CSS Variables 49 31 9.1
@supports 28 22 13 9

Common use Cases

Theming by class, by style, box-shadow transition | default default values

CSS Variables enable theming
independent of CSS structure

CSS Variables make
responsive design easier

Cool use cases

CSS Variables enable you to
set multiple properties at once

No inherit from box-shadow, invalid at computed value time

CSS Variables enable you to
create custom longhands

inline style too

CSS Variables enable you to
define your own properties

CSS Variables & SVG

CSS variables + SVG =♥️

CSS Variables & JavaScript

			// Get variable from inline style"--foo");

			// Get variable from wherever

			// Set variable on inline style"--foo", 38 + 4);

			var root = document.documentElement;

			document.addEventListener("mousemove", evt => {
				let x = evt.clientX / innerWidth;
				let y = evt.clientY / innerHeight;"--mouse-x", x);"--mouse-y", y);

			for (input of document.querySelectorAll("input")) {"--value", input.value);

			document.addEventListener("input", evt => {
				var input =;"--value", input.value);

			for (let el of document.querySelectorAll(".scrolling")) {
				el.addEventListener("scroll", evt => {
					let maxScroll = el.scrollHeight - el.offsetHeight;
					let scroll = el.scrollTop / maxScroll;"--scroll", scroll);

The allowed syntax for custom properties is extremely permissive. The <declaration-value> production matches any sequence of one or more tokens, so long as the sequence does not contain <bad-string-token>, <bad-url-token>, unmatched <)-token>, <]-token>, or <}-token>, or top-level <semicolon-token> tokens or <delim-token> tokens with a value of "!".

In addition, if the value of a custom property contains a var() reference, the var() reference must be valid according to the specified var() grammar. If not, the custom property is invalid and must be ignored.

The values of custom properties, and the values of var() functions substituted into custom properties, are case-sensitive, and must be preserved in their original author-given casing. (Many CSS values are ASCII case-insensitive, which user agents can take advantage of by "canonicalizing" them into a single casing, but that isn’t allowed for custom properties.)

The initial value of a custom property is an empty value; that is, nothing at all. This initial value has a special interaction with the var() notation, which is explained in the section defining var().

Custom properties are ordinary properties, so they can be declared on any element, are resolved with the normal inheritance and cascade rules, can be made conditional with @media and other conditional rules, can be used in HTML’s 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.

CSS Variables are a revolution for
separation of style and behavior

🔮 Future 🔮

Native mixins are coming!