In this tutorial, I’ll show you how to create scroll-based animations with fullPage.js and Animate.css—a cross-browser library of CSS animations.
Our fullPage.js and Animate.css Demo
Here’s our demo, but you’ll need to open it on a large screen, as the animations will fire only when the viewport size is at least 1,300px wide.
Required Libraries
For this tutorial, beyond the required files of fullPage.js and Animate.css, I’ve also incorporated Bootstrap 5’s CSS file. This isn’t vital; I added it only because I wanted to take advantage of Bootstrap styles.
With that in mind, if you look under the Settings tab of our demo pen, you’ll see that there are three external CSS files and one external JavaScript file.






The Process
Our page comprises four sections; each one filling the page (thanks to fullPage). Users will jump to the next section by scrolling, or navigating via the pagination links on the right. Each time that happens, we’ll trigger some animations, like bringing the images into position, for example.

First, Customize fullPage a Bit
We’ll customize fullPage a little bit so the sections’ content will sit in the center unless their content exceeds the viewport height. In this scenario, a vertical scrollbar will appear. This is only useful on small screens where the elements are stacked and the animations don’t play. On large screens, we expect that all elements will appear on the screen without any scrollbars.



Use the onLeave Callback
We need to take advantage of the “callback” functions that fullPage provides. More specifically, in our case, we want to animate the second, third, and fourth sections, so we’ll use the onLeave
callback. If we wanted to animate the first section, we could have used the afterLoad
callback. In the same way, for animating the slides we should use the afterSlideLoad
and onSlideLeave
callbacks.
Dynamically Add Animations
We’ll dynamically add CSS animations provided by the Animate.css library.
Use the animate-delay
CSS Property
We’ll also animate elements sequentially using the animate-delay
CSS property. Now, let’s dive into the page structure!
The Sections’ Structure
All page sections will have a similar structure.
Let’s consider the markup of the second section, where we have three images and a button:
1 | <sectionclass="section text-center"> |
2 | <divclass="container"> |
3 | <divclass="row"> |
4 | <divclass="col-sm-4 animate__animated"data-animation="animate__fadeInUpBig"style="--index: 1"> |
5 | <imgwidth="300"height="350"src="nature.jpeg"class="img-fluid"alt=""> |
6 | </div> |
7 | <divclass="col-sm-4 animate__animated"data-animation="animate__fadeInUpBig"style="--index: 2"> |
8 | <imgwidth="300"height="350"src="people.png"class="img-fluid"alt=""> |
9 | </div> |
10 | <divclass="col-sm-4 animate__animated"data-animation="animate__fadeInUpBig"style="--index: 3"> |
11 | <imgwidth="300"height="350"src="tech.jpeg"class="img-fluid"alt=""> |
12 | </div> |
13 | </div> |
14 | <divclass="last animate__animated"data-animation="animate__rollIn"style="--index: 6"> |
15 | <buttontype="button"class="btn btn-lg">A Simple Button</button> |
16 | </div> |
17 | </div> |
18 | </section> |
Here we add the animate__animated
class to the elements that we’re going to animate. Each one of them will receive a different animation effect. This will depend on the value of their data-animation
attribute. All possible values will come from the available animation names that Animate.css provides.
Each element will also receive an inline style. The value of the index
CSS variable will determine the start of their animation. This technique, which we’ve seen in other tutorials, will let us create staggering animations.
Finally, the last animated element (the element with the largest index
value) will receive the last
class. You’ll see why in a moment.
fullPage Customization
Let’s discuss two fullPage customizations that we’re going to do.
First, fullPage provides a few properties for specifying the scrolling behavior of the sections like the scrollOverflow
one which is set by default to true
. This will create a scrollbar for that particular section in case its content is bigger than its height. However, that can cause a problem; scrollbars will appear instantly during the animation effects in case the animated elements are coming out of view. This is something that happens in our case!



To avoid this behavior, we’ll disable the section scrolling initially and allow it only when the last animated element (the one with the last
class) of the target section finishes its animation.
Secondly, on large screens (this makes sense when also the height is big enough) where we animate the elements, we want the fp-overflow
element to occupy the full section height and not being just centered within the section.



To overcome this layout issue, we’ll take advantage of auto margins!
Alternatively, instead of adding this customization, we could use fullPage’s built-in approach and set scrollOverflow
to false
. However, this will prevent sections from showing overflowing content and might be risky in cases where we don’t have full control of the sections’ content.
All in all, here are the important styles:
1 | /*CUSTOM VARIABLES HERE*/ |
2 | |
3 | .fp-overflow{ |
4 | display:flex; |
5 | height:100vh; |
6 | } |
7 | |
8 | .fp-overflow>*{ |
9 | padding-top:5vh; |
10 | padding-bottom:5vh; |
11 | margin-top:auto; |
12 | margin-bottom:auto; |
13 | } |
14 | |
15 | .animate__animated{ |
16 | animation-delay:calc(var(--index)*0.3s); |
17 | } |
18 | |
19 | @media(min-width:1300px){ |
20 | .fp-is-overflow>.fp-overflow{ |
21 | overflow:hidden; |
22 | } |
23 | } |
JavaScript: fullPage Initialization
With all the above in mind, here’s the plugin's initialization:
1 | newfullpage("#fullpage",{ |
2 | navigation:true, |
3 | licenseKey:"gplv3-license", |
4 | onLeave:function(origin,destination,direction,trigger){ |
5 | handleAnimations(destination); |
6 | } |
7 | }); |
8 | |
9 | consthandleAnimations=(destination)=>{ |
10 | if(window.matchMedia("(min-width: 1300px)").matches){ |
11 | constdestinationAnimatedEls=destination.item.querySelectorAll( |
12 | ".animate__animated" |
13 | ); |
14 | for(constelofdestinationAnimatedEls){ |
15 | constdataset=el.dataset; |
16 | el.classList.add(dataset.animation); |
17 | if(el.classList.contains("last")){ |
18 | el.addEventListener("animationend",()=>{ |
19 | destination.item.querySelector(".fp-overflow").style.overflow= |
20 | "auto"; |
21 | }); |
22 | } |
23 | } |
24 | } |
25 | }; |
Pay attention to the animationend
event that we use to determine when the sections’ scrollbar should be released.
At this point, we also don’t focus on things on resize.
Conclusion
Done, folks! In this tutorial, we learned how we can combine the fullpage.js and Animate.css libraries to build scroll-based animations.
Keep in mind that this implementation makes sense only on large screens when all elements appear and there aren’t any scrollbars. Of course, in your own projects, you can build on this implementation and customize it according to your needs. fullPage is full of handy properties and functions.
As always, thanks a lot for reading!