Animating Background Gradients using CSS3 vs Canvas
A New Portfolio #
In the process of making a new portfolio site for my work, I decided I wanted to try to make a small jQuery plugin that transitions background gradients behind my headline text.
I noticed two different ways a person could approach this animation:
- Using CSS3 Gradients
- Using HTML5 Canvas.
My jQuery Plugin Setup #
For a comparison, I set up 2 identical plugins that functioned essentially the same except for the portion that sets the gradient.
I won’t completely go over the details of the plugin (unless requested), but basically I set up both plugins so that it looked like this:
$('.js-gradient-bg').gradientBG({
bgColors: [ 'rgb(76,89,199)', 'rgb(97,151,219)', 'rgb(35,235,198)', 'rgb(173,123,227)', 'rgb(122,107,209)', 'rgb(105,168,201)', 'rgb(24,184,237)'],
duration: 4000,
gradientType: 'leftright',
steptime: 60
});
Using the array of RGB colors, the background gradient would cycle every 4 seconds, with a 60 millisecond interval between incremental color steps.
Animating Background with CSS3 Gradients #
First I tried using the CSS3 property ‘linear-gradient’ to transition background colors. I looped through every gradient between one color setting to the next one. Once it was up and running, it looked pretty smooth. But then, I looked in the Chrome Developer tools and I noticed it was performing pretty slow.
Because of all the painting, it was constantly sitting around 45fps, which is not a great place to be. I planned to add even more animations to the page too, so this had to be improved.
Animating Background with HTML5 Canvas #
After seeing that using CSS3 Gradients was pretty slow, I tried using Canvas to display the transitioning gradients. Instead of changing the background with CSS3, I used canvas’ ‘createLinearGradient’ and incrementally set new background gradient colors.
var grd = this.context.createLinearGradient(0, 0, this.canvasWidth, this.canvasHeight);
grd.addColorStop(0, colorLeft);
grd.addColorStop(1, colorRight);
this.context.fillStyle = grd;
this.context.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
So, every step (60 milliseconds), I was using this bit of code to redraw a new gradient that filled the entire background. Because it was a <canvas>
element, I also had to add a bit of js to make it full-screen/responsive.
Peeking into Chrome’s dev tools, it was remarkable to see how quick the paint times were for this approach. While it was functioning just as well as the CSS3 approach, I did notice that there is a very slight ripple effect that’s created by repainting the canvas so often (see below). It also momentarily bugged out on page resizing, since the canvas needs to be resized with js.
CSS3 Linear-Gradient or HTML5 Canvas? #
Even though the CSS3 property ‘linear-gradient’ looked slightly smoother, I decided to use HTML5 Canvas for transitioning my background gradients. Even though it has a slight ripple effect and bugs out for a moment on window resizing, the improved paint time makes it well worth it.