When we watch a website that has cool animations, we tend to stay on the website for a long time.
It could be said that these animation features could help attract visitors to your website.
Today, I'll share with you guys how to implement fade-in animation on scroll with Vanilla Javascript.
Using IntersectionObserver to monitor if the element that you plan to animate is in the browser or not, you can make a fade-in animation that fires when the element enters the browser.
Sample & Goals
Here are two samples.
The first one is added fade-in animation on scroll for one container includes five items.
The second sample is applied fade-in animation for every five-item.
You can try to scroll and check animation again and again.
Blueprint
First, prepare an element that you want to apply fade-in animation with HTML. And add '.appear' class. (Class name doesn't matter. Whatever you want.)
Elements with the '.appear' class will be the target of the fade-in animation.
Second, write a fade-in animation with CSS. When the '.inview' class is added to an element with a '.appear', set the opacity to 1 and transform: translateY(40px) to none.
Third, control the '.inview' class using IntersectionObserver of Javascript.
Throughout this article, we will use the unified class name to explain.
- '.appear' class → It adds to the element's class which you want to apply fade-in animation.
- '.inview' class → It will be added when the element that has 'appear' class enters the browser.
Let's try to make a fade-in animation on scroll!
Monitor a single element and control classes with IntersectionObserver
1.Prepare the element that has the 'appear' class according to the above blueprint.
<div class="container appear">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
</div>
This time, I applied the 'appear' class at container div.
2.Prepare CSS animation.
.appear {
transition: all 0.8s;
opacity: 0;
transform: translateY(40px);
}
.appear.inview {
opacity: 1;
transform: none;
transition-delay: 0.3s;
}
If an element has an 'appear' class, it's applied 'transition','opacity' and 'transform'.
In this case, I wrote the CSS so that once the 'inview' class is added, the translateY value will disappear. By doing so, the element that has 'appear' class will move upward from 40px down from its normal position.
And then the element can appear to the browser changing 'opacity'.
3.Monitor an element and control classes with IntersectionObserver
You can use the IntersectionObserver to determine if the monitored element is in the browser or not and add or remove the 'inview' class.
const appear = document.querySelector('.appear');
const cb = function(entries){
entries.forEach(entry => {
if(entry.isIntersecting){
entry.target.classList.add('inview');
}else{
entry.target.classList.remove('inview');
}
});
}
const io = new IntersectionObserver(cb);
io.observe(appear);
I will explain how I am using 'IntersectionObserver'.
1.Get the element to be monitored.
const appear = document.querySelector('.appear');
In this case, it's the 'container' class div.
2.Write a callback function.
const cb = function(entries){
entries.forEach(entry => {
if(entry.isIntersecting){
entry.target.classList.add('inview');
}else{
entry.target.classList.remove('inview');
}
});
}
IntersectionObserver passes a callback function as a parameter.
In this code, a callback function is named 'cb'.
To find out which elements have been intersected using 'forEach'.
The 'entry.isIntersecting' can be used for the condition that the element is inside the screen.
And the if-else statement can be used to write code to add or remove classes.
If the element is intersected, add 'inview' class to 'appear' class.
3.Call the constructor to create an Intersection observer and pass a callback function.
const io = new IntersectionObserver(cb);
4.Specifies the target element to be monitored.
io.observe(appear);
In this code, it's monitoring the element with 'appear' class.
Monitor multiple elements(have same class name) and control classes with IntersectionObserver
1.Prepare elements that have the 'appear2' class according to the above blueprint.
<div class="container">
<div class="item appear2">1</div>
<div class="item appear2">2</div>
<div class="item appear2">3</div>
<div class="item appear2">4</div>
<div class="item appear2">5</div>
</div>
In this second pattern, we will implement an animation in which multiple elements fade-in and out at different times.
I added 'appear2' class to each item.
2.Prepare CSS animation using Sass.
.appear2 {
transition: all 0.8s;
opacity: 0;
transform: translateY(20px);
&.inview2 {
opacity: 1;
transform: none;
@for $i from 1 through 5 {
&:nth-child(#{$i}) {
transition-delay: $i * 0.1s;
}
}
}
}
'.appear2'class is the same styles as '.appear'.
However, '.inview2' class has for loop section to transition-delay.
In Sass, we can handle Loop conveniently.
I'm going to put transition-delay on each element.
I use a loop statement to add a time delay for each element to appear one by one.
If you want to write it in CSS, it would be long like this.
.appear2.inview2 {
opacity: 1;
transform: none;
}
.appear2.inview2:nth-child(1) {
transition-delay: 0.1s;
}
.appear2.inview2:nth-child(2) {
transition-delay: 0.2s;
}
.appear2.inview2:nth-child(3) {
transition-delay: 0.3s;
}
.appear2.inview2:nth-child(4) {
transition-delay: 0.4s;
}
.appear2.inview2:nth-child(5) {
transition-delay: 0.5s;
}
As you can see, Sass is powerful and useful, and I personally like Sass.
3.Monitor multiple elements and control classes with IntersectionObserver
Finally, We will control classes using IntersectionObserver.
In this sample, we need to monitor multiple elements, so we will use a loop statement to implement it.
const items = document.querySelectorAll('.appear2');
const active = function(entries){
entries.forEach(entry => {
if(entry.isIntersecting){
entry.target.classList.add('inview2');
}else{
entry.target.classList.remove('inview2');
}
});
}
const io2 = new IntersectionObserver(active);
for(let i=0; i < items.length; i++){
io2.observe(items[i]);
}
We have to get multiple elements this time, so I'll use
"querySelector*All*".
const items = document.querySelectorAll('.appear2');
This part is the same as the above.
const active = function(entries){
entries.forEach(entry => {
if(entry.isIntersecting){
entry.target.classList.add('inview2');
}else{
entry.target.classList.remove('inview2');
}
});
}
const io2 = new IntersectionObserver(active);
This last section is different from the previous one.
Since there are multiple elements with the 'appear2' class, we will write the code to monitor all the elements with the 'appear2' class using a loop statement.
for(let i=0; i < items.length; i++){
io2.observe(items[i]);
}
This'.observe()' is used in this way '.observe(Elements to be monitored)'.
If you want to monitor multiple elements that have different classes, you could write like this.
const item1 = document.querySelector('.item1');
const child = document.querySelector('.child');
const element = document.querySelector('.element');
///...(omitted)...IntersectionObserver
io2.observe(item1);
io2.observe(child);
io2.observe(element);
We can make fade-in animation on scroll using IntersectionObserver at last!
This is my first article about tech so I hope you guys could understand it easily.
Thank you.
Top comments (6)
Cool.
Thank you!
This is great – thank you.
Any idea how would stop it from repeating as you scroll back up the page (i.e. only fade-in once)?
I added Sample 3 in the Code Pen. Please check it.
It just remove else part and add 'entry.unobserve(entry.target)'.
Thank you!
Thanks so much <3
This is awesome. Any idea in second sample how to trigger animation when full element is visible on screen?