Build Design Systems With Penpot Components
Penpot's new component system for building scalable design systems, emphasizing designer-developer collaboration.

CSS-Tricks | Chris Coyier
In CSS, some properties have shorthand. One property that takes separated values. Syntactic sugar, as they say, to make authoring easier. Take transition
, which might look something like:
.element {
transition: border 0.2s ease-in-out;
}
We could have written it like this:
.element {
transition-property: border;
transition-duration: 0.2s;
transition-timing-function: ease-in-out;
}
Every “part” of the shorthand value has its own property it maps to. But that’s not true for everything. Take box-shadow
:
.element {
box-shadow: 0 0 10px #333;
}
That’s not shorthand for other properties. There is no box-shadow-color
or box-shadow-offset
.
That’s where Custom Properties come to save us!
We could set it up like this:
:root {
--box-shadow-offset-x: 10px;
--box-shadow-offset-y: 2px;
--box-shadow-blur: 5px;
--box-shadow-spread: 0;
--box-shadow-color: #333;
}
.element {
box-shadow:
var(--box-shadow-offset-x)
var(--box-shadow-offset-y)
var(--box-shadow-blur)
var(--box-shadow-spread)
var(--box-shadow-color);
}
A bit verbose, perhaps, but gets the job done.
Now that we’ve done that, remember we get some uniquely cool things:
We can change individual values with JavaScript. Like:
document.documentElement.style.setProperty("--box-shadow-color", "green");
--box-shadow-color: blue
on any selector more specific than the :root, we’ll override that color.Fallbacks are possible too, in case the variable isn’t set at all:
.element {
box-shadow:
var(--box-shadow-offset-x, 0)
var(--box-shadow-offset-y, 0)
var(--box-shadow-blur, 5px)
var(--box-shadow-spread, 0)
var(--box-shadow-color, black);
}
How about transforms? They are fun because they take a space-separated list of values, so each of them could be a custom property:
:root {
--transform_1: scale(2);
--transform_2: rotate(10deg);
}
.element{
transform: var(--transform_1) var(--transform_2);
}
What about elements that do have individual properties for their shorthand, but also offer comma-separated multiple values? Another great use-case:
:root {
--bgImage: url(basic_map.svg);
--image_1_position: 50px 20px;
--image_2_position: bottom right;
}
.element {
background:
var(--bgImage) no-repeat var(--image_1_position),
var(--bgImage) no-repeat var(--image_2_position);
}
Or transitions?
:root {
--transition_1_property: border;
--transition_1_duration: 0.2s;
--transition_1_timing_function: ease;
--transition_2_property: background;
--transition_2_duration: 1s;
--transition_2_timing_function: ease-in-out;
}
.element {
transition:
var(--transition_1_property)
var(--transition_1_duration)
var(--transition_1_timing_function),
var(--transition_2_property)
var(--transition_2_duration)
var(--transition_2_timing_function),
}
Dan Wilson recently used this kind of thing with animations to show how it’s possible to pause individual animations!
Here’s browser support:
Green indicates full support at the version listed (and above). Yellow indicates partial support. Red indicates no support. See Caniuse for full browser support details.
Chrome | Opera | Firefox | IE | Edge | Safari |
---|---|---|---|---|---|
49 | 36 | 31 | No | 15 | 9.1 |
iOS Safari | Opera Mobile | Opera Mini | Android | Android Chrome | Android Firefox |
---|---|---|---|---|---|
9.3 | 37 | No | 56 | 57 | 52 |
Now that CSS Custom Properties are a Thing, All Value Parts Can Be Changed Individually is a post from CSS-Tricks
AI-driven updates, curated by humans and hand-edited for the Prototypr community