DEV Community

Shiho Kazama | mia
Shiho Kazama | mia

Posted on • Updated on

Fade-in animation on scroll with IntersectionObserver(Vanilla JS)

 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>
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

I will explain how I am using 'IntersectionObserver'.


1.Get the element to be monitored.

const appear = document.querySelector('.appear'); 
Enter fullscreen mode Exit fullscreen mode

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');
    }
  });
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

4.Specifies the target element to be monitored.

io.observe(appear);
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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;
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

'.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;
}
Enter fullscreen mode Exit fullscreen mode

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]);
 }

Enter fullscreen mode Exit fullscreen mode

We have to get multiple elements this time, so I'll use
"querySelector*All*".

const items = document.querySelectorAll('.appear2');
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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]);
 }
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode



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)

Collapse
 
zyabxwcd profile image
Akash

Cool.

Collapse
 
miacan2021 profile image
Shiho Kazama | mia

Thank you!

Collapse
 
iwishyoucouldtalk profile image
Jason Reynolds

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)?

Collapse
 
miacan2021 profile image
Shiho Kazama | mia

I added Sample 3 in the Code Pen. Please check it.
It just remove else part and add 'entry.unobserve(entry.target)'.
Thank you!

Collapse
 
iwishyoucouldtalk profile image
Jason Reynolds

Thanks so much <3

Collapse
 
nithinkjoy profile image
Nithin K Joy

This is awesome. Any idea in second sample how to trigger animation when full element is visible on screen?