(You can download the assets here: Animation Assets)
I wanted to do a videogame conference website, so instead of a static overlay background, why not an animated one?
Like this:
And that's what I'm going to teach you to do in the rest of this article using only HTML and CSS.
So let's get right in.
This step by step guide assumes that you have some basic knowledge of HTML and CSS. If this is your first approach to this technology I recommend these sites: https://www.freecodecamp.org/learn/ or https://www.codecademy.com/catalog/language/html-css to get familiar with it before reading further in.
First, we set up the basic HTML markup for a website. Nothing fancy, we add the corresponding <title> tag and now it's time to start filling up the <body>.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./style.css">
<title>Background Animation</title>
</head>
<body>
</body>
</html>
Next, we open up a <section> element, but you can use a <div> or another one of your choosing. After this, the heading for the title and a <div> that's going to act as a container for the character animation. Inside this <div>, we add the <img> element with the spritesheet.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./style.css">
<title>Background Animation</title>
</head>
<body>
<section>
<h1>
Character Animation with Parallax Background using HTML & CSS
</h1>
<div>
<img src="spr_m_traveler_walk_anim.png" alt="Walking animation">
</div>
</section>
</body>
</html>
Now it's time to add classes, you can name them any way you want for the sake of this example. But if you're going to apply this on a project, try to use a CSS naming convention like BEM.
We give classes to all the elements that are going to be involved in the animation.
<body>
<section class="animation-section">
<h1>
Character Animation with Parallax Background using HTML & CSS
</h1>
<div class="animation-section_character">
<img class="animation-section_character-sprites" src="spr_m_traveler_walk_anim.png" alt="">
</div>
</section>
</body>
After all these steps, your webpage should be looking like this:
Now it's styling time!
Let's get rid of the margin and padding of the page and hide the overflow on the X-axis and make the Y-axis auto. This will make the character and background appear as they were only wide as one frame.
* {
margin: 0;
padding: 0;
overflow-x: hidden;
overflow-y: auto;
}
Now the section element, but before we style it, we have to check the dimension of the background image. In our example, this is 2560px width and 200px height. So our section element should have the same height and double the width. This is because we want the animation to be smooth and endless on the X-axis.
.animation-section {
height: 200px;
width: 5120px;
}
Next in line is the styling of the h1 element. We change the font-size, center it and give it a 100vw and a height of 50px.
h1 {
margin-top: 20px;
font-size: 2.5em;
text-align: center;
width: 100vw;
height: 50px;
}
For the character container, we need to give it the same width and height of one frame of the spritesheet. In our example, it should be 64 x 64px. (We get this value dividing the width size of the spritesheet by the number of frames of the image. 512px/8 = 64px). Also we have to give it a position relative, as the image is going to be absolute positioned.
.animation-section_character {
position: relative;
width: 64px;
height: 64px;
}
And for the <img> element class, add a position absolute.
.animation-section_character-sprites {
position: absolute;
}
So now the before and after of the character should look like this.
It's time to put some life into this!
In the previous step, we already narrowed the character container to show only one frame.
Now it's time to animate this. We need to change the frame that is showing inside the character container, with the next one, and so on. We can achieve this using the CSS animation property on the <img> element:
animation: <animation-name | animation-duration | animation-timing-function | animation-delay | animation-iteration-count | animation-direction>
To use this property, first, we have to declare a new rule called @keyframes. This is going to allow us to change styles at certain times.
We need a name and a property to change. I recommend using transform over other options that could achieve the same result. You can check here the detailed explanation of the why : High Performance Animation.
Now using the transform property, we are going to move the image, from (0%) 0px to (100%) -512px on the X-axis using the translateX value.
@keyframes walking-animation {
from {
transform:translateX(0);
}
to {
transform: translateX(-512px);
}
}
With our @keyframes rule established we can now start to complete our animation.
Now we define the animation-name value using the name created in the @keyframes rule.
Next, an animation duration, in this example we use 1s, but you can use whatever value you see fit.
The animation-timing-function we are going to use is steps, which is perfect for this. Here we only need to provide the number of frames we have on the spritesheet, in our case is 8.
The animation-iteration-count, in this case, is infinite because we want our animation to be endless.
The animation-delay and animation-direction are not used in this example.
.animation-section_character-sprites {
position: absolute;
animation: walking-animation 1s steps(8) infinite;
}
Tadaaa! It's alive!
If everything has gone ok, the character should be walking on the screen. But it's looking kind of empty right? Let's give it a floor to run on and a background!
Now we are going to make a moving floor, for that we are going to use pseudo-elements. These are elements that allow us to insert content into the page without the need of being in the HTML. How cool is that?!
For this, we are going to use the class we gave to the <section> element. This is going to act as the parent of the pseudo-elements, so we need to give it a relative position.
.animation-section {
height: 200px;
width: 5120px;
position: relative;
}
We now define the pseudo-selector ::before for the <section> class.
We give it a content property blank because we only need the background-image, which is 2560px wide.
The position we use is absolute, and a 100% width and height.
.animation-section::before {
content: "";
background-image: url(./article-bg.png);
position: absolute;
width: 100%;
height: 100%;
}
The ground needs to move from right to left so we have to use the @keyframes rule again.
We give it a descriptive name and repeat the use of the transform property and translateX.
@keyframes bg-animation {
to {
transform: translateX(-2560px);
}
}
Now we add the animation on the ::before pseudo-class, this time we give it a 20s duration and a linear animation-timing-function.
.animation-section::before {
content: "";
background-image: url(./article-bg.png);
position: absolute;
width: 100%;
height: 100%;
animation: bg-animation 20s linear infinite;
}
We also need to add some margin-top to the character container to position it right on top of the floor
.animation-section_character {
margin-top: 35px;
width: 64px;
height: 64px;
position: relative;
}
So far it should look like this:
We are lacking a background, so we are going to use the other pseudo-element ::after on the same <section> to add it.
The content is blank, same as ::before, the position is also absolute, this time we need a top: 0 and the same 100% width and height.
The new things we have to add here are a z-index, because we need this to stay behind all other elements. Also a linear-gradient as a background color along with the picture of the background elements. And some opacity to give that "far away" effect.
For the animation, we use the same one as the ::before pseudo-element, only this time, we make the duration 100s. This will make the background move slower than the floor, creating that awesome parallax effect.
.animation-section::after {
content: "";
background-image:
url(./article-bg-4.png),
linear-gradient(0deg, rgba(64,59,59,1) 15%, rgba(2,8,17,1) 100%);
position: absolute;
top: 0;
width: 100%;
height: 100%;
z-index: -2;
animation: bg-animation 100s linear infinite;
opacity: 0.5;
}
As you can see we are almost done!
The only thing that's left is to highlight the title a little bit more, so we are going to use a pseudo-element again and make a dark-background for the <h1>.
h1::before {
content: "";
position: absolute;
top: 0;
left: 0;
background-color: black;
width: 100%;
height: 100%;
opacity: 0.5;
z-index: -1;
}
And that's it! Congratulations! now you have a cool animation you can use as you see fit.
You can keep improving it by adding more elements using the same technique. Another thing to keep in mind is that if you use pixel-art or something similar, you can use this property on the image:
image-rendering: pixelated; /* For Chrome */
image-rendering: crisp-edges; /* For Firefox */
This will keep your pixels looking good even when you scale them.
Here's the link for the full live version on codepen
All the assets used were downloaded from OpenGame Art
Overlay pictures used created by Cindy Shan