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)

Picture of me
Hi, I’m Lea


I grew up in Lesbos, Greece

…which technically makes me geographically Lesbian

I make stuff

CSS WG Invited Expert

MIT HCI researcher @ CSAIL

CSS Secrets by O’Reilly ★★★★★ on Amazon

CSS Variables

$color: #ff0066;

@color: #ff0066;


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

CSS Variables work like
normal CSS properties

inheritance, cancel inheritance, inherit keyword

CSS Variables are
inherited properties
but you can change that

					--img: "cat1.jpg";
					background: url("img/" var(--img));
CSS limitation

					--img: "img/cat1.jpg";
					background: url(var(--img));
CSS bug

					--img: url("img/cat1.jpg");
					background: var(--img);

CSS variables + url() =💩


  • --foo:; is invalid
  • --foo: ; is valid
  • --foo--FOO
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?!

Invalid at computed-value time = initial

				var(--color1, var(--color2, var(--color3, red)))
background: var(--nonexistent, none, yellowgreen);

					/* Equivalent to: */
					background: none, yellowgreen;

Cycles make variables invalid
at computed-value time

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

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

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

Show division not working

Number → unit: calc(var(--foo) * 1px)
Unit → number:

Use variables for pure data,
not CSS values

Try to animate --color | show that var() is ok

CSS Variables in @keyframes?

[CSS variables] can even be tran­sitioned or ani­mated, but since the UA has no way to interpret their con­tents, they always use the "flips at 50%" behav­ior that is used for any oth­er pair of val­ues that can’t be intelligently interpolated.

CSS Custom Properties for Cascading Variables Module Level 1

CSS variables + animations =💩

🔮 Near Future 🔮

Chrome Firefox Edge Safari
CSS.registerProperty() ⛳️

CSS variables + animations =🔮❤️

Common use Cases

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

CSS Variables enable theming
independent of CSS structure

Default default values are possible

			--colorD: var(--color, black);
			/* use --colorD instead of --color internally */

CSS Variables make
responsive design easier

Cool use cases

CSS Variables enable you to
set multiple properties at once

CSS Variables let you create
single property mixins
(like function currying, in programmerese)

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
(in some cases)

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);


<html mv-app
      style="--mouse-x: [$mouse.x / innerWidth];
	          --mouse-y: [$mouse.y / innerHeight];">

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

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

Show value indicator

CSS variables are awesome

			for (let element of document.querySelectorAll(".typing")) {
				let length = element.textContent.length;"--length", length);

CSS variables are awesome

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

CSS Variables are a revolution for
separation of style and behavior