Animations are a great way to make a website more interesting; let me show you how.
Most animations depend on JavaScript in one form or another, especially when they deal with complicated sequences or occur after a user interaction such as scrolling or clicking.
However, if we’re building a simple animation that doesn’t require any user interaction at all, then it can be done purely with CSS.
1. Markup With HTML
For the structure of our webpage, we’ll break down the banner into the individual elements we’ll be animating.
1 |
<div class="container"> |
2 |
<div class="split-screen"></div> |
3 |
<div class="background-image"></div> |
4 |
<div class="content"> |
5 |
<p>Hello <span class="comma">,</span></p> |
6 |
<p>World</p> |
7 |
</div>
|
8 |
</div>
|
2. Styling With CSS
Now we can style the layout of our page. Let’s begin with the static elements i.e. the elements that don’t need any animation.
1 |
body { |
2 |
margin: 0; |
3 |
background-color: #b1bcbf; |
4 |
} |
5 |
|
6 |
.container { |
7 |
width: 100%; |
8 |
height: 100vh; |
9 |
position: relative; |
10 |
} |
11 |
|
12 |
.background-image { |
13 |
width: 50%; |
14 |
position: absolute; |
15 |
top: 0; |
16 |
bottom: 0; |
17 |
left: 0; |
18 |
margin: auto; |
19 |
background-image: url("https://images.pexels.com/photos/1261728/pexels-photo-1261728.jpeg"); |
20 |
background-size: cover; |
21 |
} |
Here’s what our page looks like currently:



3. Animating With CSS
Once we have our static styling done, we can move on to the animated elements. The main thing to keep in mind when working with CSS animations is monitoring the timing of each animated element to make sure they flow smoothly together. Luckily, you can view the details of any animation on a webpage using the Chrome DevTools Animation Inspector. This chart gives us a clear idea of the start point and during of every animated element in our webpage.
Let’s take a look at the timeline for our demo:



Now we have an idea of what the timeline looks like, let’s recreate it starting with the split screen animation.
The initial styling for the element is set to completely cover the page:
1 |
.split-screen { |
2 |
width: 100%; |
3 |
background-color: #2c2d2b; |
4 |
position: absolute; |
5 |
right: 0; |
6 |
top: 0; |
7 |
bottom: 0; |
8 |
z-index: 2; |
9 |
}
|
Then we’ll define a new animation using the @keyframes
property.
Keyframes are used to determine the timeline of each animation.
For example, if we have an animation lasting 2 seconds and we set a keyframe property opacity: 1 at 50%, this means the element will reach an opacity of 1 at 1s. We can also use the from
and to
keywords to specify the start and end keyframes.
We want to set the split-screen element to go from 100% to 50% of the page width.
1 |
@keyframes reduceSize { |
2 |
from { |
3 |
width: 100%; |
4 |
}
|
5 |
to { |
6 |
width: 50%; |
7 |
}
|
8 |
}
|
Assign the Animation Keyframes to an Element
Now we can assign this animation to the split-screen
element using the animation-name
property. We can also control the timing of the animation using the animation-duration
and animation-delay
properties. Based on animation chart above, we want the split-screen animation to start 500ms after the page has loaded so we’ll give it a delay of 0.5s:
1 |
animation-name: reduceSize; |
2 |
animation-duration: 1.5s; |
3 |
animation-delay: 0.5s; |
This is what our animation looks like now (again, hit Rerun to see the animation):
Animation Fill Mode
From the pen above, we’ll notice that the element reverts back to its original state after animation. We can prevent this from happening by using the animation-fill-mode
property. This property allows us to control the state of an animated element before and after the animation is carried out.
1 |
animation-name: reduceSize; |
2 |
animation-duration: 1.5s; |
3 |
animation-delay: 0.5s; |
4 |
animation-fill-mode: forwards; |
By setting the property to forwards
, we’re specifying that the animation should maintain the state of its last keyframe. This is our updated animation:
Using Shorthand Property is Even Better
We can use the animation shorthand property to apply all the animation styling so far. Now our split screen styling looks like this:
1 |
.split-screen { |
2 |
width: 100%; |
3 |
background-color: #2c2d2b; |
4 |
position: absolute; |
5 |
left: 0; |
6 |
top: 0; |
7 |
bottom: 0; |
8 |
z-index: 2; |
9 |
animation: reduceSize 1.5s 0.5s forwards; |
10 |
}
|
The animation-duration value should be placed before the animation-delay value.
Next Animation
The next animation we apply to the split screen banner is moving it to the right of the screen. We’ll define a keyframe property to handle this:
1 |
@keyframes moveRight { |
2 |
from { |
3 |
left: 0%; |
4 |
}
|
5 |
to { |
6 |
left: 50%; |
7 |
}
|
8 |
}
|
We’ll set the timing of the animation to start 3s after the page loads and last for a total of 1.5s. We can also combine animations in CSS:
1 |
.split-screen { |
2 |
width: 100%; |
3 |
background-color: #2c2d2b; |
4 |
position: absolute; |
5 |
left: 0; |
6 |
top: 0; |
7 |
bottom: 0; |
8 |
z-index: 2; |
9 |
animation: |
10 |
reduceSize 1.5s 0.5s forwards, |
11 |
moveRight 1.5s 3s forwards; |
12 |
}
|
Animation on Page Content
Next, we’ll animate the content on the page.
There are three animations to be set for the content:
- Content fades in while sliding up from the bottom of the page
- Content slides to the right
- Content changes text colour from white to a background image
Let’s define the keyframes for each. For sliding the content to the right, we can reuse the already defined moveRight animation.
1 |
@keyframes fadeInUp { |
2 |
from { |
3 |
transform: translateY(100vh); |
4 |
opacity: 0; |
5 |
}
|
6 |
to { |
7 |
transform: translateY(0); |
8 |
opacity: 1; |
9 |
}
|
10 |
}
|
11 |
|
12 |
@keyframes changeBackground { |
13 |
to { |
14 |
background-image: url("https://images.pexels.com/photos/1261728/pexels-photo-1261728.jpeg"); |
15 |
background-size: 200%; |
16 |
background-position: center; |
17 |
background-clip: text; |
18 |
-webkit-background-clip: text; |
19 |
color: transparent; |
20 |
}
|
21 |
}
|
For the changeBackground keyframe, we use the background-clip
property to set the text colour as a background image instead of a single colour.
Now let’s style the content. Since we’re working with animation delays, we’ll need to apply the start keyframe of the animation directly to the content or this will cause a jar when the animation starts. Take a look at what happens if we don’t have the initial content styling matching the keyframe start style:
The content is visible on page load before the opacity and transform properties in the fadeInUp
animation are applied, so we’ll need to include those properties in the content styling:
1 |
.content { |
2 |
color: white; |
3 |
font-size: 10vw; |
4 |
text-transform: uppercase; |
5 |
position: absolute; |
6 |
width: fit-content; |
7 |
height: fit-content; |
8 |
top: 0; |
9 |
left: 0; |
10 |
right: 0; |
11 |
bottom: 0; |
12 |
margin: auto; |
13 |
z-index: 4; |
14 |
opacity: 0; |
15 |
transform: translateY(100vh); |
16 |
animation: |
17 |
fadeInUp 2s 0.5s, |
18 |
moveRight 1.5s 3s, |
19 |
changeBackground 1.5s 3s; |
20 |
animation-fill-mode: forwards; |
21 |
}
|
One Last Detail
Finally, we apply one last animation to the span containing a comma just for fun:
1 |
.content .comma { |
2 |
color: #2c2d2b; |
3 |
opacity: 1; |
4 |
animation: fadeOut 0.5s forwards 2.5s; |
5 |
}
|
6 |
|
7 |
@keyframes fadeOut { |
8 |
from { |
9 |
opacity: 1; |
10 |
}
|
11 |
to { |
12 |
opacity: 0; |
13 |
}
|
14 |
}
|
We’re Done!
And that’s that—we’re done with our CSS animated banner!