CSS Variables


Quick, what are the two most useful features of every CSS pre-processor out there? Top of that list are probably variables and concatenating files. There have been rumblings about CSS getting native variables for a few years now and they’re finally in the wild in major browsers.

These native variables are called “custom properties”. To me they’re one of the coolest things in CSS today. They give you as a developer the ability to natively keep values consistent without the help of a build process.

Browser Support

from Can I Use

Using Variables

You can define a custom property in the root of your project and call it with the var() function. The only trick to defining a custom property is that you need to prefix them with the double dashes --. It may be a little odd at first, but it prevents naming collisions with reserved words and values. It’s also worth noting these custom property names are case sensitive.

Custom properties store any value you want. It can be a color, a calc() function, measurement, a string or any other value you would normally define in CSS.

:root {
	--base-color: #147aab;
}

a {
	color: var(--base-color);
}

You can also define a custom property at the selector level and then that property is scoped to that parent selector.

.Block {
	--theme: #147aab;
	border-top-color: var(--theme);
	padding: 1rem;
}

.Block__title {
	color: var(--theme);
}

You can optionally set a fallback in the var() function if that named variable isn’t available. For example, if the variable --theme isn’t available, it will use the hex value in the second parameter.

.Block {
	color: var(--theme, #ffc600);
}

You can redefine custom properties at breakpoints.

:root {
	--blue: #5886a7;
}

html {
	background: var(--blue, #ffc600);
}

@media only screen and (min-width: 20rem) {
	:root {
		--blue: #147aab;
	}
}

Working with Numbers

Custom properties store values but you can’t interpolate them like you can with Sass with the #{$variable}px or similar syntax. You can store a unit-less number but you can’t just append a unit when you’re calling that custom property. To achieve this you can combine the unit-less value with the calc() function.

:root {
	--size: 1.5;
}

h1 {
	font-size: var(--size) rem; /* Doesn't Work */
	font-size: calc(var(--size) * 1rem); /* Works Perfectly */
}

Mixin-like Properties

There’s another spec related to custom properties with the @apply rule. It’s similar to a Sass mixin in that it applies groups of styles, but it’s static so it doesn’t take any parameters like Sass mixins would.

:root {
	--awesome-headline: {
		text-transform: uppercase;
		letter-spacing: 2px;
		color: var(--base-color);
	}
}

h1 {
	@apply --awesome-headline;
}

As of the time of writing this post, you can only use @apply in Chrome behind a feature flag. But maybe that will change soon. There is a PostCSS plugin that will let you compile those values.

Examples

This is an example of applying custom property to a parent element and applying it child elements.

See the Pen Custom Properties by Charles Peters (@charlespeters) on CodePen.

This is an example of updating a custom property’s value with JavaScript.

See the Pen Changing CSS Custom Props by Charles Peters (@charlespeters) on CodePen.

Further Reading