To better understand what we’re going to build, check out the demo page. Be sure to click on the menu links to repeat the page loading JavaScript animation.
As both JS animations have similarities, I’ll borrow some content sections from the previous tutorial. This will help keep each tutorial detailed and independent.
For this tutorial our web page loading animation demo won’t live on CodePen. As we need different pages to showcase the JS page loading, I decided that it’s better to host it on GitHub. Here’s the project structure for the JS page loading:
1 |
panels-animation/ |
2 |
├── about.html |
3 |
├── contact.html |
4 |
├── index.html |
5 |
├── main.css |
6 |
└── main.js |
Before we continue, it’s worth noting that the inspiration for this page loading animation JavaScript demo is taken from the rather lovely Nine Orchard’s website.
Let’s describe the markup for the index.html
page. This will be similar to the other pages.
Inside it, we’ll place:
main
element where the page’s main content will live.
Additionally, we’ll import:
With all the above in mind, here’s the associated markup for the animation with JavaScript:
1 |
|
2 |
lang="en">
|
3 |
|
4 |
charset="utf-8">
|
5 |
name="viewport" content="width=device-width, initial-scale=1">
|
6 |
rel="preconnect" href="https://fonts.gstatic.com">
|
7 |
rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap">
|
8 |
rel="stylesheet" href="main.css">
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
href="index.html">Home
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
Home Page |
37 |
|
38 |
|
39 |
|
40 |
|
41 |
"main.js"> |
42 |
|
43 |
|
Consider the inline styles that we add to the panels. As we’ll see later, we’ll use the index
CSS variable to animate them. The bigger the value, the more time it’ll take for the associated element to animate.
Next, we’ll continue with some CSS variables and reset styles:
1 |
:root { |
2 |
--panel-width: calc(100% / 7); |
3 |
--darkblue: #02020c; |
4 |
--white: #fff; |
5 |
--lightgray: #fafafb; |
6 |
}
|
7 |
|
8 |
* { |
9 |
padding: 0; |
10 |
margin: 0; |
11 |
box-sizing: border-box; |
12 |
}
|
13 |
|
14 |
ul { |
15 |
list-style: none; |
16 |
}
|
17 |
|
18 |
a { |
19 |
color: inherit; |
20 |
text-decoration: none; |
21 |
}
|
22 |
|
23 |
h1 { |
24 |
font-size: 3rem; |
25 |
}
|
26 |
|
27 |
body { |
28 |
height: 100vh; |
29 |
font-family: "Montserrat", sans-serif; |
30 |
color: var(--white); |
31 |
background: var(--darkblue); |
32 |
overflow: hidden; |
33 |
}
|
Three things to note:
panel-width
variable will determine the panel width.
Let’s now concentrate on the main styles for the page loading JavaScript animation. We’ll leave out the header styles as they haven’t any importance.
When the page loads, the following page loading JavaScript animations have to play in this order:
During the first two steps, the panels will be transitioned with some delay. As we’ve discussed before, this will depend on the value of their index
variable.
To create a sequence of tweens as we did the last time with GSAP’s Timeline, we’ll take advantage of a lesser-known event called transitionend
. This event fires each time a CSS transition finishes and gives us the ability to synchronize page loading JS animations.
Of course, we aren’t interested in all transitions, instead, we only care about the panels’ transitions and specifically the transitions of the last JS animated panel. In our case, the last animated panels will be the first and seventh (last) ones as both have index: 3
.
As you’ll see in the code, we’ll work with the last one, but we could equally have used the first one. To better understand it, try to give the selected panel a large delay of around 1s and see how the JavaScript animations get out of sync.
In terms of the code logic, we’ll do the following things in this order:
loaded
class to the body
.
body
. The first time we’ll add the second-round
class, while the second time, we’ll add the third-round
.
After the completion of our transitions, the body
will have these classes:
Here’s the JavaScript code:
1 |
const body = document.body; |
2 |
const lastPanel = document.querySelector(".panels .panel:last-child"); |
3 |
|
4 |
window.addEventListener("load", () => { |
5 |
body.classList.add("loaded"); |
6 |
|
7 |
lastPanel.addEventListener("transitionend", () => { |
8 |
if (body.classList.contains("second-round")) { |
9 |
body.classList.add("third-round"); |
10 |
} else { |
11 |
body.classList.add("second-round"); |
12 |
}
|
13 |
});
|
14 |
});
|
Instead of the load
event, we could have used the DOMContentLoaded
event.
And the corresponding styles of the page loading JS animation:
1 |
.loaded .panels .panel { |
2 |
clip-path: inset(0); |
3 |
transition-delay: calc(var(--index) * 0.06s); |
4 |
}
|
5 |
|
6 |
.loaded.second-round .panels .panel { |
7 |
clip-path: inset(0 0 100% 0); |
8 |
}
|
9 |
|
10 |
.loaded.third-round { |
11 |
overflow: auto; |
12 |
}
|
13 |
|
14 |
.loaded.third-round .page-main > div > * { |
15 |
opacity: 1; |
16 |
transform: none; |
17 |
}
|
Congrats, folks! We managed to build an attractive JavaScript page loading animation by staggering animations thanks to the transitionend
event. Obviously, for more heavy use of page loading JS animations, a library like GSAP is a more robust approach to follow. Feel free to extend the demo as you wish and share it with me!
As always, thanks a lot for reading!
Take a look at these projects on Tuts+ that use the clip-path
property to apply different kinds of animations.