Creating a rainbow animation
When I started thinking about a new logo for a new project, a rainbow was involved. I figured it would be nice to do an animation: stacking the seven colors one by one and then creating a subtle transition between the colours.
To be more precise:
- the first colour starts the animation, and ends at the same time as the animation of the last color;
- when every block is in its place, the seven colours transform into a subtle gradient.
It should look something like this:

(If you don’t want to read the explanation below and want to go for the good stuff straight away: here’s the Codepen.)
HTML
The HTML is rather straightforward:
| |
(S)CSS
I’m using SCSS here, for easy use of variables and the ability of creating mixins.
Colours
First, let’s create the colours of the rainbow as variables. I used this image, because I’m lazy and didn’t want to fire up Photoshop to extract the colors from an image. The variables then look like this:
| |
Keyframes
For creating the animation, the parent container <div class="rainbow"></div> needs position: relative;. The child <div class="rainbow__color"></div> gets assigned position:absolute. That way, the children elements will get positioned relative to the parent container. In other words: they know where to start and stop (and – not unimportantly – stay still).
The animation is created by keyframes. The colour starts at the top and has no height (at 0%). It grows, and moves downwards until it reaches its final position and height (at 80%). In the last part the colour changes into a gradient (at 100%).
Each colour needs its own keyframe, because each is placed on a different position in the rainbow. The first colour (red) needs top: 100%; at 100% of the keyframe, while the seventh colour (violet) needs top: 0;. Every other colour needs to be positioned somewhere in between. There’s a little math involved to get this right for each color:
distanceToTop = totalHeight - (totalHeight / totalColors) * numberOfColor
For example: the third colour (yellow) has distanceToTop of 100% - (100% / 7) * 3 = 57.14286%, so the keyframe becomes 100% { top: 57.14286%; }. The code looks like this:
| |
Animation
Furthermore, each colour needs its own animation, because each colour needs a different animation-duration and animation-delay. If every element was given the same duration and delay, all elements would start and finish animating at the same time, and that’s not what I meant to do. Each colour has to start at a set interval, but they have to end simultaneously. But how to calculate the different amounts of animation-duration and animation-delay?
Calculating animation-delay
The total duration of the complete rainbow animation is 2 seconds. In those 2 seconds, all seven colours have to animate, but they can’t start at the same time. In other words, they need a different animation-delay. The math looks like this:
animationDelay = totalDuration * ((numberOfColor - 1) / totalColors)
The first colour starts without delay, but the second colour has to wait 1/7th of 2 seconds, the third colour has to wait 2/7th of 2 seconds, et cetera.
Calculating animation-duration
The animation duration is the opposite of the animation delay.
animationDuration = totalDuration - ((numberOfColor - 1) / totalColors) * totalDuration
That means the first colour has 2 seconds to complete its animation (2s - 0 = 2s), the second colour has 2s - (1/7 * 2s) = 1.714286s, the third colour has 2s - (2/7 * 2s) = 1.428572s, et cetera.
Animation with properties
So, the animation of each colour looks like this:
| |
I used the shorthand notation. The order is as follows:
- the name of the keyframes-sequence the animation has to use;
- the duration of the animation;
- the style of the animation;
- the fill-mode of the animation (this has to be
forwardsso that it preserves its final state); and - the delay of the animation
And now for the result!
Hmmm, something’s wrong…
That’s almost what I had in mind, but something’s off. The last part doesn’t animate: there’s a sudden change between the colour and the gradient. Why isn’t this working?
Pseudo-element to the rescue
It turns out that gradients are not animatable. Luckily, this article provided a solution: use an extra or a pseudo-element. When both elements are stacked upon each other, it’s possible to transition the opacity — which is animatable — of the top element. Brilliant. The keyframe looks as simple as it is:
| |
I decided to use an pseudo-element, which looks like this in the (S)CSS:
| |
Setting opacity: 0; means it stays hidden until the animation is triggered. The animation has a duration of 1 second, and a delay of 2 seconds — which corresponds with the total duration of the movement of the colours.
Keyframes
Now that the change in colour to gradient has its own animation on a separate (pseudo-)element, it’s time to create the keyframe for the colours. It looks like this:
| |
(Notice I inserted a step at 20%. I thought that gave the animation a better effect. You may of may not disagree.)
Result
Now it’s working like I wanted it to work as you can see in this Codepen.
Satisfying.


