CSS Custom Properties + JS Animations = ๐ฅ
CSS Custom Properties kick the maintainability of our JS-based animations into the stratosphere! ๐
When creating JavaScript-based animations that affect elements in the DOM, it is almost guaranteed that we will be modifying style properties inside our animation loop. For many of us, this would look something like the following:
let xPos = 0;
ย
function animate(timestamp) {
xPos += 10;
ย
circle.style.transform = `translate3d(${xPos}px, 0, 0)`;
ย
if (Math.abs(xPos) >= 900) {
xPos = -500;
}
ย
requestAnimationFrame(animate)
}
In this snippet, we are animating a circle elementโs position from left to right. We do this by setting the transform directly:
circle.style.transform = `translate3d(${xPos}px, 0, 0)`;
There is nothing directly wrong with this approach, but it does bring up some awkward patterns:
Specifying the entire CSS string is wordy ๐
If we ever need to adjust the behavior of our animation, we will need to muck around with the CSS inside our JavaScript ๐
By having the CSS embedded as a string in JavaScript, we lose code editor niceties like syntax highlighting, error detection, linter support, and more ๐
This is where CSS Custom Properties help greatly. With CSS Custom Properties, we can decouple our CSS from JavaScript and focus only on the specific value that needs changing. For example, the above snippet can be rewritten as follows starting with our CSS:
#circle {
--horizontalPos: 100px;
transform: translate3d(var(--horizontalPos), 0, 0);
}
The horizontal position of our translated3d transfrom
is defined by the --horizontalPos
property. Inside our animation loop, we modify this property value:
let xPos = 0;
function animate(timestamp) {
xPos += 20;
circle.style.setProperty("--horizontalPos", xPos + "px");
if (Math.abs(xPos) >= 900) {
xPos = -500;
}
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
Instead of setting the full CSS string like we did earlier, our code can be simplified as follows:
circle.style.setProperty("--horizontalPos", xPos + "px");
Everything else revolving around how this value is used and which CSS property will ultimately consume it is fully handled in our CSS:
transform: translate3d(var(--horizontalPos), 0, 0);
This gives us the best of many worlds where CSS-related things are in the appropriate CSS regions and JS-related things are in the appropriate JavaScript regions. If we ever decide to change how our animation works, modify how we define our transform
, or do any host of related things, we just have to make the changes in our CSS. As long as the --horizontalPos
custom property isnโt renamed or changed, we donโt ever have to fiddle with JavaScript at all. Really cool, right?
The Video Goes Deeper
To go a little deeper and see the full example in all its animation-filled epicness, I made a short 10-minute video that youโll love:
I find that seeing a video after getting a brief text-based overview helps me learn and remember what I just learned better. If that describes you, then do check out all of my other videos and subscribe to be notified of new videos I post.
(PS: Our #codecat Pixel makes a guest appearance for a good part of this video, so thatโs a bonus if you like to see me balance doing a demo while keeping a cat calm!)
Conclusion
I hope you found this more technically-focused content helpful as you blend the worlds of code, art, and animation!
If you have any questions or have ideas on what technical topics youโd like me to cover next, please do post on the forums. Lastly, if you are so inclined, please do me a favor and like or retweet my Tweet around this topic to help the Twitter algorithm show it to more people:
![Twitter avatar for @kirupa](https://substackcdn.com/image/twitter_name/w_96/kirupa.jpg)
![](https://substackcdn.com/image/fetch/w_600,h_314,c_fill,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F785c5805-e4a4-46ff-987d-99ce29e1a67b_1280x720.jpeg)
See you all next time!
Cheers,
Kirupa ๐
I LOVE css variables, but I wish we could write things like.....
```transform: translate3d(var(--horizontalPos)px, 0, 0);```
...and I wish we could animate them...bring on @property Firefox and Safari!!!! How long do we have to wait for Houdini?!?!