Trigger a CSS Keyframe Animation by Scrolling

Let's say I have an element with animation:

#element {
  animation: Fade 3s linear 1s forwards;
}

@keyframes Fade {
  /* do stuff */
}

      

How can I only start this animation when the user scrolls down? Vanilla JS, jQuery, ScrollMagic, GSAP / TweenMax, however you want to do this.

Will adding the animation property itself cause the effect? So the user scrolls to a certain point / element and then I apply something like $('#element').css('animation', 'Fade 3s linear 1s forwards');

:?

+2


source to share


2 answers


Add a class to the element that animates when the user scrolls down.

pseudocode

on window scroll {
  if (scroll pos > x) {
    element.addclass("animateMe");
  }
}

      

Demo



http://jsbin.com/zuqexigepe/edit?html,output

If you want the animation to run every time the user scrolls past a certain point, you can simply change the scroll event to remove the class, for example:

$(window).scroll(function () {
  if($(window).scrollTop() > 0) {
    element.addClass("animateMe");
  }
  else {
    element.removeClass("animateMe");
  }
});

      

+2


source


The posted (and accepted) answer is technically correct, but there are currently more performance-friendly ways to achieve this. If you want to run animations on multiple elements instead of just one, viewing those multiple elements can cause performance degradation. See an example of this question . Disclaimer: This question also has my answer, I will only copy my work in this answer:

To solve this problem in a modern modern way, it is best to use Intersection Observer (IO) for that .

With IO, you can observe one (or more) elements and react as soon as they appear or intersect with each other.



To use IO, you first need to set parameters for it, then determine which items to track, and finally, determine what exactly happens after the IO starts.

An example ( from here ), with one minimal modification: I removed the IO even if the animation hasn't happened yet. I moved the call to unobserve inside the check if the element is visible.

const SELECTOR = '.watched';
const ANIMATE_CLASS_NAME = 'animated';

const animate = element => (
  element.classList.add(ANIMATE_CLASS_NAME)
);

const isAnimated = element => (
  element.classList.contains(ANIMATE_CLASS_NAME)
);

const intersectionObserver = new IntersectionObserver((entries, observer) => {
  entries.forEach((entry) => {
    
    // when element is in viewport,
    // animate it!
    if (entry.intersectionRatio > 0) {
      animate(entry.target);
      // remove observer after animation
      observer.unobserve(entry.target);
    }
  });
});

// get only these elements,
// which are not animated yet
const elements = [].filter.call(
  document.querySelectorAll(SELECTOR),
  element => !isAnimated(element, ANIMATE_CLASS_NAME)
);
//console.log(elements);

// start observing your elements
elements.forEach((element) => intersectionObserver.observe(element));
      

.h100 {
height: 100vh;
}

.watched {
 opacity: 0;
 transition: opacity .5s;
}

.watched.animated {
opacity: 1;
}
      

<div class="h100">
scroll down
</div>
<div class="watched">
I'm watched
</div>
<div class="h100">
Another element, keep scrolling
</div>
<div class="watched">
I'm also watched
</div>
      

Run codeHide result


0


source







All Articles