Fade in animation on scroll with vanilla JavaScript and CSS Vanilla JSCSS

You can animate an element to fade-in when a user scrolls down to that element to make a webpage feel more dynamic. This is how to fade-in on scroll with vanilla JavaScript and CSS.

The first thing to do in order to fade elements in on scroll is select the elements that you want to fade in with JavaScript. The simplest way to do this is to give them all the same class and use querySelectorAll() to return a NodeList representing the elements.

// select all .project elements
const projects = document.querySelectorAll(".project");

// select all .project elements except the first one
const projects = document.querySelectorAll(".project:not(:first-child)");

If your elements that you want to fade in on scroll are all below the fold (not visible at the top of the page before the user scrolls) you can simply get all the elements with that class using the first example above. However if one of your elements is above the fold, you'll want to exclude that from the selection and have that one show normally because you are first going to hide the elements with JavaScript and then wait for a scroll event and check the scroll value before showing them and you want to make sure that everything above the fold is immediately visible to the user.

The next step is to hide the elements that you want to fade-in on scroll. You can use .forEach() on the NodeList returned by querySelectorAll() to loop over the elements and add a class which you can target with CSS to hide them.

projects.forEach(function(project) {
  project.classList.add("hide-for-fade-in");
});

The class I've added to each element is 'hide-for-fade-in'.

Next, create a CSS rule for that class and set the opacity to 0%.

If you would also like the elements to move up slightly as they fade in, you could also set a margin-top property in the CSS rule and set the value to the distance away from its default position that you want it to start moving up from.

Then in the same CSS rule, you can add a transition property to animate the opacity and margin when the values are changed.

/* opacity only */
.hide-for-fade-in {
  opacity: 0%;
  -webkit-transition: opacity 0.5s;
  -o-transition: opacity 0.5s;
  transition: opacity 0.5s;
}
/* opacity and margin */
.hide-for-fade-in {
  opacity: 0%;
  margin-top: 50px;
  -webkit-transition: opacity 0.5s, margin 0.5s;
  -o-transition: opacity 0.5s, margin 0.5s;
  transition: opacity 0.5s, margin 0.5s;
}

Then create the class that will be added to the elements with JavaScript to fade them in. This class just needs to contain the end value of the transition such as opacity: 100% and margin-top: 0.

/* opacity only */
.fade-in {
  opacity: 100%;
}
/* opacity and margin */
.fade-in {
  opacity: 100%;
  margin-top: 0;
}

You can use forEach() again to add the second class that will update the values and make the elements fade in, but this time you'll also need to wait for a scroll event inside the forEach().

Then you'll also want to get the current scroll position. You can get this with window.scrollY. Then you can check the scroll position against each element's offsetTop.

projects.forEach(function(project) {
  window.addEventListener("scroll", function() {
    let scroll = window.scrollY;
    if (scroll > project.offsetTop - 500) {
      project.classList.add("fade-in");
    }
  });
});

The '- 500' in the conditional statement makes sure the element fades in when it is 500px from the top of the viewport instead of at the top of the viewport. Experiment with this value as your own site may be better suited to a different value.

Thanks for reading.
Ryan

Published on 30 Aug 2022