In this article, I will share with you an application of CSS custom properties that I have found useful.
If you're like me, who like to cramp as many animations in the page as possible for micro interactions sake (just kidding, don't do that), you would be writing a lot of CSS animations with @keyframes
.
@keyframes
is notorious for its inflexibility, once it is declared, the values are then set in stone. If you have a set of @keyframes
with the same behavior but different values, you'll need to make another set. This result in a lot of @keyframes
that are similar but with a little variations in the numbers. Letβs take a look at the example below:
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fade-in-a-little {
0% {
opacity: 0;
}
100% {
opacity: 0.3;
}
}
.item-1 {
animation: fade-in 300ms ease;
}
.item-2 {
animation: fade-in-a-little 300ms ease;
}
In the example above, we have 2 items with 2 different animations that are similar, with only slight difference in the opacity
value at 100%
.
Now imagine what this would turn into when applied to more items. As the website scale up, what you'll end up with is 100s of similar @keyframes
, bloating up the CSS file. We can't have that. π
CSS custom properties to the rescue
CSS custom properties (also known as CSS variables), are most widely applied for theming. It can also be used to make @keyframes
reusable! (If you want to learn about CSS custom properties, see here)
Let's refactor our previous example with CSS custom properties!
@keyframes fade {
0% {
opacity: var(--fade-start, 0);
}
100% {
opacity: var(--fade-end, 1);
}
}
.item-1 {
animation: fade 300ms ease;
}
.item-2 {
--fade-end: 0.3;
animation: fade 300ms ease;
}
fade-in-a-little
@keyframes
is taken out as it is not needed anymore. We now have only 1 set of @keyframes
fade
, and apply CSS custom properties to the starting opacity value and the ending opacity value with:
opacity: var(--fade-start, 0); // start
opacity: var(--fade-end, 1); // end
In this example, we have 2 custom properties: --fade-start
and --fade-end
. These variables are applied using var()
function (read more about it here). The var()
function accepts 2 parameters, a value and a fallback (default value).
So with this line opacity: var(--fade-start, 0);
, if --fade-start
is not set, 0 will be applied instead. The same goes to --fade-end
.
The end result we get here is a set of @keyframes
that can fade
between opacity: 0
and opacity: 1
by default and be tuned within the scope of a CSS selector. π€―
Wait... so to fade out? Yes! Instead of declaring another set of @keyframes
for fade-out
, you can reuse fade
and set --fade-start
as 1, and --fade-end
to 0, like so:
.item-to-fade-out {
--fade-start: 1;
--fade-end: 0;
animation: fade 300ms ease;
}
With CSS custom properties, @keyframes
can now be function like, where the variable parts can be defined at a later stage, making @keyframes
reusable. Yay DRY β€οΈοΈ
Time to bust out the Codepen
One @keyframes
to fade
it all
Summary
Fading animation is one of the most common animation on the web, now with CSS custom properties we can reduce our CSS bloat significantly while having as many variations of it as we'd like.
Consider applying this to @keyframes
that you find yourself repeating a lot with many little variations.
Hope you'll find this useful!
Top comments (5)
@j3nnning thanks for the post, nicely laid out. CSS custom properties (variables) are amazing.
One pain point I usually face is when there is a need for IE11 support (quite common) and appropriate polyfill has to be applied stackoverflow.com/questions/464299...
Great point. If your project requires support for IE11 and below, I would suggest refrain from implementing CSS custom properties on critical features and only leave it for fluff, things that are ok to break.
In the accepted answer from the link that you've provided (great link btw), it only works with custom properties in the root level. In the context of reusable keyframes, it would defeat the purpose because you want to be able to set the value at the selector level.
As a fallback, you can simply write another line with absolute value before the
var()
line, so any browser that aren't supportingvar()
will fallback to it. i.e.Any browser where
var()
isn't supported would simply fade from 0 to 1, your animation would not break completely, imo that would be a good enough fallback.Love the code pen addition!
This is amazing! Thank you!
Thank you for this, I never thought of it!