Animated Clouds - Part 1

If you want to know how to animate clouds, similar to the drifting clouds in the title bar, then you are reading the right post!

In Part 1 we will cover how to set up animated clouds using CSS animations and variables.

Part 1: CSS Animations & CSS Variables permalink#

  1. Setting up clouds in HTML & CSS
  2. Moving clouds across the screen
  3. Changing the speed of clouds
  4. Changing the size of clouds
  5. Adding a perception of depth to the clouds
  6. Bringing it all together
  7. Next steps

All examples from the steps below are available on CodePen.


1. Setting up the cloud in HTML & CSS permalink#

Before you get started you will need to find yourself an image of a cloud with a transparent background.


The following HTML and CSS will position a single, stationary, cloud at the left hand side of the sky.

HTML
<div class="sky">
<div class="cloud" style="top: 50%"></div>
</div>
CSS
.sky {
background: #95d2ec;
overflow: hidden;
position: relative;
width: 100%;
height: 50px;
}

.cloud {
background-image: url(/cloud.png);
background-size: contain;
background-repeat: no-repeat;
background-position: center;
position: absolute;
transform: translateY(-50%);
width: 50px;
height: 50px;
}

2. Moving the clouds permalink#

We need to use CSS animations to move the clouds across the sky.


The following CSS will define the move animation and add it to the cloud. The animation will move the cloud across the sky, from left to right, over a period of 60 seconds. The cloud will then reappear at the left and repeat the cycle indefinitely.

CSS
.cloud {
...
animation-name: move;
animation-duration: 60s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}

@keyframes move {
0% {
margin-left: -50px;
}
100% {
margin-left: 100%;
}
}

3. Changing the speed of the clouds permalink#

To adjust the speed of the clouds we can change the animation-duration property within the cloud class. This applies the same speed to every cloud which you may not want. Instead we are going to make use of CSS variables so we can change the speed of individual clouds.


The following HTML sets up three clouds of varying speeds using a new --speed variable.

HTML
<div class="sky" style="height: 150px">
<div class="cloud" style="top: 20%"></div>
<div class="cloud" style="top: 50%; --speed: 0.5"></div>
<div class="cloud" style="top: 80%; --speed: 2"></div>
</div>

The following CSS uses the --speed variable when calculating the animation-duration of the cloud and sets --speed to a default value of 1.

CSS
.cloud {
...
--speed: 1;
animation-duration: calc(60s / var(--speed));
}

4. Changing the size of the clouds permalink#

It looks a bit odd that all clouds are the same size so let's add another CSS variable --scale which we will use to change the size of a cloud.


The following HTML sets up three clouds of varying sizes using a new --scale variable.

HTML
<div class="sky" style="height: 200px">
<div class="cloud" style="top: 15%"></div>
<div class="cloud" style="top: 45%; --scale: 2"></div>
<div class="cloud" style="top: 75%; --scale: 1.5"></div>
</div>

The following CSS uses the --scale variable when calculating the width and height properties of the cloud and sets --scale to a default value of 1.

To ensure larger clouds start their animation out of view we also update the first frame of the move animation by multiplying the margin-left by the --scale.

CSS
.cloud {
...
--scale: 1;
width: calc(50px * var(--scale));
height: calc(50px * var(--scale));
}

@keyframes move {
0% {
margin-left: calc(-50px * var(--scale));
}
100% {
margin-left: 100%;
}
}

5. Adding a perception of depth to the clouds permalink#

Next we will add a perception of depth between the clouds with the addition of a third CSS variable --depth. Similar to the other variables, --depth will also be used as a scalar. Where 1 has no visual effect on the cloud and the closer the depth gets to zero the further away the cloud disappears into the distance.

When a cloud appears further back it will be smaller, slower and appear darker (really just a lower opacity).


The following HTML sets up three clouds of varying depths using a new --depth variable.

HTML
<div class="sky" style="height: 150px">
<div class="cloud" style="top: 20%; --depth: 0.7"></div>
<div class="cloud" style="top: 50%; --depth: 0.85"></div>
<div class="cloud" style="top: 80%; --depth: 1"></div>
</div>

The following CSS uses the --depth variable when calculating the width, height, animation-duration and opacity properties of the cloud and sets --depth to a default value of 1.

Again, we also ensure clouds start their animation just out of view by updating the first frame of the move animation by multiplying the margin-left by the --scale and the --depth.

CSS
.cloud {
...
--depth: 1;
animation-duration: calc(60s / (var(--speed) * var(--depth)));
opacity: var(--depth);
width: calc(50px * var(--scale) * var(--depth));
height: calc(50px * var(--scale) * var(--depth));
}

@keyframes move {
0% {
margin-left: calc(-50px * var(--scale) * var(--depth));
}
100% {
margin-left: 100%;
}
}

6. Bringing it all together permalink#

Finally, we can combine the usage of our three CSS variables --speed, --scale and --depth to create a simulation of drifting clouds which hopefully looks awesome!


The following HTML sets up three clouds of varying speeds, sizes and depths using the three CSS variables --speed, --scale and --depth respectively.

HTML
<div class="sky">
<div class="cloud" style="top: 15%; --scale: 1.5; --depth: 0.85"></div>
<div class="cloud" style="top: 45%; --speed: 0.75; --depth: 0.85"></div>
<div class="cloud" style="top: 75%; --scale: 2"></div>
</div>

The following CSS is a complete example of everything covered in this post.

  • The animation-duration is affected by both the --speed and the --depth
  • The opacity is affected by only the --depth
  • The width and height are affected by both the --scale and the --depth
CSS
.sky {
background: #95d2ec;
overflow: hidden;
position: relative;
width: 100%;
height: 150px;
}

.cloud {
--depth: 1;
--scale: 1;
--speed: 1;

animation-name: move;
animation-duration: calc(60s / (var(--speed) * var(--depth)));
animation-timing-function: linear;
animation-iteration-count: infinite;

background-image: url(/cloud.png);
background-size: contain;
background-repeat: no-repeat;
background-position: center;

position: absolute;
transform: translateY(-50%);

opacity: var(--depth);

width: calc(50px * var(--scale) * var(--depth));
height: calc(50px * var(--scale) * var(--depth));
}

@keyframes move {
0% {
margin-left: calc(-50px * var(--scale) * var(--depth));
}
100% {
margin-left: 100%;
}
}

7. Next steps permalink#

Later in Part 2 we will cover how you can use JavaScript to programmatically create clouds with randomised positions, speeds, sizes and depths at varying intervals.


Back to top