Animating CSS gradients

Animating CSS gradients

Recently I was asked to build a holding page that included an animating CSS gradient. My first reaction was: “Easy. CSS animation.” And I was quite wrong. JavaScript to the rescue!

My initial assumption was based on thinking that a CSS gradient was a CSS property that you can transition, much like background-color. CSS gradients are actually dimension-less background images which display at the size of the element. And background images we can’t animate with CSS as it’s image-data and not a numeric thing that CSS can cycle, like, say, a hex value or margin value.

Suppose you want to animate one gradient to another, what do you do?
Simple. You use JavaScript to interpolate the steps and write an inline style on the element to animate the transition.

See the Pen xLoiH by Mike Byrne (@13twelve) on CodePen.

Colours are kind of brilliant when you break them down into RGB values and much easier to work with than hex values. The script creates an array of simple two stop gradients, then breaks down the differences between the RGB values and incrementally alters them based on time and frame per second variables.

My example uses 60 frames per second because 60fps is some kind of front end developer target; though being an old front end developer with Flash optimisation experience where we used to aim for 25fps, targeting 60 seems high to me and so I’d be tempted to use 30 fps. Less DOM writes are probably better for the browser too and less likely to trigger the fans on your laptop.

A few of things to point out:

– No jQuery, remember, I’m trying to use jQuery less.

– The script only checks for browser support of CSS gradients after it has tried to write a gradient into the page. Why? Seemed like a good time to check if writing the gradient was successful or not. If it wasn’t successful the setInterval is cleared and the loop ended. Maybe thats progressive-ish enhancement? I’m not sure.

– The script rounds the RGB values to integers using bitwise operators, fondly remembering the JSPerf tests Seb Lee-Delisle did while optimising his canvas JavaScripts a few years ago. Bitwise operators reduce code readability and recently it seems browser performance with Math.round() has increased to match; plus the native function will get performance optimisations as part of the browser JavaScript engine wars and hacks won’t. So I should perhaps switch, but for now my nostalgia wins.

– The script checks to see if the RGB values on each step of the animation are different and if not, doesn’t try to write to the page. Currently it’s checking a generated string, eg: rgb(255,100,0) to rgb(254,101,1). This may not be the fastest way and is something I need to research. From observing console.logs it seems this basic checking stops around a third of page writes.

– For performance sake, I wouldn’t have multiple animated gradients on one page and I don’t think I’d ask the browser to do any other DOM writing while this script is running. Each time the inline style is written to the page the browser has to generate the gradient background image and render it. I have no hard facts on this, but my gut instinct tells me that rendering lots of gradients sequentially like this is a tough thing for the browser to do. And of course, it isn’t hardware accelerated like CSS transitions are. So use with caution.