How to Create an Animated Loader Using HTML and CSS
Step-by-Step Guide to Making an Animated Loader with HTML and CSS
Creating an animated loader is a fundamental skill for web developers. In this guide, we'll walk you through the process of building a captivating animated loader using HTML and CSS. This project is part of day 40 of the #100DaysOfCode Challenge. You can download the full source code here.
Step 1: Setting Up the HTML Structure
First, we'll create the basic structure for our loader in an HTML file. This involves setting up the document and creating the necessary elements.
<!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>Animated Loader</title>
</head>
<body>
<div class="loader">
<div class="box box0"><div></div></div>
<div class="box box1"><div></div></div>
<div class="box box2"><div></div></div>
<div class="box box3"><div></div></div>
<div class="box box4"><div></div></div>
<div class="box box5"><div></div></div>
<div class="box box6"><div></div></div>
<div class="box box7"><div></div></div>
<div class="ground"><div></div></div>
</div>
</body>
</html>
This HTML sets up the basic loader structure. Each box
and the ground
will be animated to create a dynamic effect.
Step 2: Styling the Loader with CSS
Next, we'll use CSS to style and animate our loader. This involves defining the dimensions, colors, and animations for each element.
Basic Loader Styling
body {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
}
.loader {
--duration: 3s;
--primary: rgba(39, 94, 254, 1);
--primary-light: #2f71ff;
--primary-rgba: rgba(39, 94, 254, 0);
width: 200px;
height: 320px;
position: relative;
transform-style: preserve-3d;
}
@media (max-width: 480px) {
.loader {
zoom: 0.44;
}
}
This CSS sets up the body and loader container. The --duration
variable defines the animation duration, and --primary
and --primary-light
define the colors used.
Adding 3D Effects
.loader:before,
.loader:after {
--r: 20.5deg;
content: "";
width: 320px;
height: 140px;
position: absolute;
right: 32%;
bottom: -11px;
background: #fff;
transform: translateZ(200px) rotate(var(--r));
animation: mask var(--duration) linear forwards infinite;
}
.loader:after {
--r: -20.5deg;
right: auto;
left: 32%;
}
The :before
and :after
pseudo-elements create the background effects, adding depth to the loader.
Animating the Ground and Boxes
.loader .ground {
position: absolute;
left: -50px;
bottom: -120px;
transform-style: preserve-3d;
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
.loader .ground div {
transform: rotateX(90deg) rotateY(0deg) translate(-48px, -120px) translateZ(100px) scale(0);
width: 200px;
height: 200px;
background: var(--primary);
background: linear-gradient(45deg, var(--primary) 0%, var(--primary) 50%, var(--primary-light) 50%, var(--primary-light) 100%);
transform-style: preserve-3d;
-webkit-animation: ground var(--duration) linear forwards infinite;
animation: ground var(--duration) linear forwards infinite;
}
.loader .ground div:before,
.loader .ground div:after {
--rx: 90deg;
--ry: 0deg;
--x: 44px;
--y: 162px;
--z: -50px;
content: "";
width: 156px;
height: 300px;
opacity: 0;
background: linear-gradient(var(--primary), var(--primary-rgba));
position: absolute;
transform: rotateX(var(--rx)) rotateY(var(--ry)) translate(var(--x), var(--y)) translateZ(var(--z));
-webkit-animation: ground-shine var(--duration) linear forwards infinite;
animation: ground-shine var(--duration) linear forwards infinite;
}
.loader .ground div:after {
--rx: 90deg;
--ry: 90deg;
--x: 0;
--y: 177px;
--z: 150px;
}
.loader .box {
--x: 0;
--y: 0;
position: absolute;
-webkit-animation: var(--duration) linear forwards infinite;
animation: var(--duration) linear forwards infinite;
transform: translate(var(--x), var(--y));
}
.loader .box div {
background-color: var(--primary);
width: 48px;
height: 48px;
position: relative;
transform-style: preserve-3d;
-webkit-animation: var(--duration) ease forwards infinite;
animation: var(--duration) ease forwards infinite;
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
.loader .box div:before,
.loader .box div:after {
--rx: 90deg;
--ry: 0deg;
--z: 24px;
--y: -24px;
--x: 0;
content: "";
position: absolute;
background-color: inherit;
width: inherit;
height: inherit;
transform: rotateX(var(--rx)) rotateY(var(--ry)) translate(var(--x), var(--y)) translateZ(var(--z));
filter: brightness(var(--b, 1.2));
}
.loader .box div:after {
--rx: 0deg;
--ry: 90deg;
--x: 24px;
--y: 0;
--b: 1.4;
}
.loader .box.box0 {
--x: -220px;
--y: -120px;
left: 58px;
top: 108px;
}
.loader .box.box1 {
--x: -260px;
--y: 120px;
left: 25px;
top: 120px;
}
.loader .box.box2 {
--x: 120px;
--y: -190px;
left: 58px;
top: 64px;
}
.loader .box.box3 {
--x: 280px;
--y: -40px;
left: 91px;
top: 120px;
}
.loader .box.box4 {
--x: 60px;
--y: 200px;
left: 58px;
top: 132px;
}
.loader .box.box5 {
--x: -220px;
--y: -120px;
left: 25px;
top: 76px;
}
.loader .box.box6 {
--x: -260px;
--y: 120px;
left: 91px;
top: 76px;
}
.loader .box.box7 {
--x: -240px;
--y: 200px;
left: 58px;
top: 87px;
}
.loader .box0 {
-webkit-animation-name: box-move0;
animation-name: box-move0;
}
.loader .box0 div {
-webkit-animation-name: box-scale0;
animation-name: box-scale0;
}
.loader .box1 {
-webkit-animation-name: box-move1;
animation-name: box-move1;
}
.loader .box1 div {
-webkit-animation-name: box-scale1;
animation-name: box-scale1;
}
.loader .box2 {
-webkit-animation-name: box-move2;
animation-name: box-move2;
}
.loader .box2 div {
-webkit-animation-name: box-scale2;
animation-name: box-scale2;
}
.loader .box3 {
-webkit-animation-name: box-move3;
animation-name: box-move3;
}
.loader .box3 div {
-webkit-animation-name: box-scale3;
animation-name: box-scale3;
}
.loader .box4 {
-webkit-animation-name: box-move4;
animation-name: box-move4;
}
.loader .box4 div {
-webkit-animation-name: box-scale4;
animation-name: box-scale4;
}
.loader .box5 {
-webkit-animation-name: box-move5;
animation-name: box-move5;
}
.loader .box5 div {
-webkit-animation-name: box-scale5;
animation-name: box-scale5;
}
.loader .box6 {
-webkit-animation-name: box-move6;
animation-name: box-move6;
}
.loader .box6 div {
-webkit-animation-name: box-scale6;
animation-name: box-scale6;
}
.loader .box7 {
-webkit-animation-name: box-move7;
animation-name: box-move7;
}
.loader .box7 div {
-webkit-animation-name: box-scale7;
animation-name: box-scale7;
}
The ground
and box
classes control the main elements of the loader. Each box
is positioned and animated to create a dynamic visual effect.
Keyframes for Animation
@-webkit-keyframes box-move0 {
12% {
transform: translate(var(--x), var(--y));
}
25%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@keyframes box-move0 {
12% {
transform: translate(var(--x), var(--y));
}
25%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@-webkit-keyframes box-scale0 {
6% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
14%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@keyframes box-scale0 {
6% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
14%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@-webkit-keyframes box-move1 {
16% {
transform: translate(var(--x), var(--y));
}
29%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@keyframes box-move1 {
16% {
transform: translate(var(--x), var(--y));
}
29%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@-webkit-keyframes box-scale1 {
10% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
18%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@keyframes box-scale1 {
10% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
18%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@-webkit-keyframes box-move2 {
20% {
transform: translate(var(--x), var(--y));
}
33%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@keyframes box-move2 {
20% {
transform: translate(var(--x), var(--y));
}
33%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@-webkit-keyframes box-scale2 {
14% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
22%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@keyframes box-scale2 {
14% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
22%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@-webkit-keyframes box-move3 {
24% {
transform: translate(var(--x), var(--y));
}
37%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@keyframes box-move3 {
24% {
transform: translate(var(--x), var(--y));
}
37%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@-webkit-keyframes box-scale3 {
18% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
26%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@keyframes box-scale3 {
18% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
26%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@-webkit-keyframes box-move4 {
28% {
transform: translate(var(--x), var(--y));
}
41%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@keyframes box-move4 {
28% {
transform: translate(var(--x), var(--y));
}
41%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@-webkit-keyframes box-scale4 {
22% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
30%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@keyframes box-scale4 {
22% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
30%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@-webkit-keyframes box-move5 {
32% {
transform: translate(var(--x), var(--y));
}
45%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@keyframes box-move5 {
32% {
transform: translate(var(--x), var(--y));
}
45%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@-webkit-keyframes box-scale5 {
26% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
34%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@keyframes box-scale5 {
26% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
34%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@-webkit-keyframes box-move6 {
36% {
transform: translate(var(--x), var(--y));
}
49%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@keyframes box-move6 {
36% {
transform: translate(var(--x), var(--y));
}
49%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@-webkit-keyframes box-scale6 {
30% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
38%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@keyframes box-scale6 {
30% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
38%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@-webkit-keyframes box-move7 {
40% {
transform: translate(var(--x), var(--y));
}
53%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@keyframes box-move7 {
40% {
transform: translate(var(--x), var(--y));
}
53%,
52% {
transform: translate(0, 0);
}
80% {
transform: translate(0, -32px);
}
90%,
100% {
transform: translate(0, 188px);
}
}
@-webkit-keyframes box-scale7 {
34% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
42%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@keyframes box-scale7 {
34% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(0);
}
42%,
100% {
transform: rotateY(-47deg) rotateX(-15deg) rotateZ(15deg) scale(1);
}
}
@-webkit-keyframes ground {
0%,
65% {
transform: rotateX(90deg) rotateY(0deg) translate(-48px, -120px) translateZ(100px) scale(0);
}
75%,
90% {
transform: rotateX(90deg) rotateY(0deg) translate(-48px, -120px) translateZ(100px) scale(1);
}
100% {
transform: rotateX(90deg) rotateY(0deg) translate(-48px, -120px) translateZ(100px) scale(0);
}
}
@keyframes ground {
0%,
65% {
transform: rotateX(90deg) rotateY(0deg) translate(-48px, -120px) translateZ(100px) scale(0);
}
75%,
90% {
transform: rotateX(90deg) rotateY(0deg) translate(-48px, -120px) translateZ(100px) scale(1);
}
100% {
transform: rotateX(90deg) rotateY(0deg) translate(-48px, -120px) translateZ(100px) scale(0);
}
}
@-webkit-keyframes ground-shine {
0%,
70% {
opacity: 0;
}
75%,
87% {
opacity: 0.2;
}
100% {
opacity: 0;
}
}
@keyframes ground-shine {
0%,
70% {
opacity: 0;
}
75%,
87% {
opacity: 0.2;
}
100% {
opacity: 0;
}
}
@-webkit-keyframes mask {
0%,
65% {
opacity: 0;
}
66%,
100% {
opacity: 1;
}
}
@keyframes mask {
0%,
65% {
opacity: 0;
}
66%,
100% {
opacity: 1;
}
}
These keyframes define the animations for each box
and the ground
. They control the movement and scaling of the elements over the specified duration.
Conclusion
By following these steps, you can create an engaging animated loader using HTML and CSS. This project enhances your web development skills and adds a professional touch to your websites. Don't forget to download the full source code here. Happy coding!