4

I am having an issue with my css anmation, it appears the animation occurs after the page loads and not when you scroll to the section, how do I make my animation happen when you scroll to the section and not after the page loads?

Here is my styling element:

.slick-slide:nth-child(odd) {
    -webkit-animation-name: fadeInLeft;
    -moz-animation-name: fadeInLeft;
    -o-animation-name: fadeInLeft;
    animation-name: fadeInLeft;
    -webkit-animation-duration: 1s;
    -moz-animation-duration: 1s;
    -o-animation-duration: 1s;
    animation-duration: 1s;
    -webkit-animation-delay: 1s;
    -moz-animation-delay: 1s;
    -o-animation-duration:1s;
    animation-delay: 1s;
}

and here are my keyframes

@-webkit-keyframes fadeInLeft {
    from {
        opacity:0;
        -webkit-transform: translatex(-10px);
        -moz-transform: translatex(-10px);
        -o-transform: translatex(-10px);
        transform: translatex(-10px);
    }
    to {
        opacity:1;
        -webkit-transform: translatex(0);
        -moz-transform: translatex(0);
        -o-transform: translatex(0);
        transform: translatex(0);
    }
}
@-moz-keyframes fadeInLeft {
    from {
        opacity:0;
        -webkit-transform: translatex(-10px);
        -moz-transform: translatex(-10px);
        -o-transform: translatex(-10px);
        transform: translatex(-10px);
    }
    to {
        opacity:1;
        -webkit-transform: translatex(0);
        -moz-transform: translatex(0);
        -o-transform: translatex(0);
        transform: translatex(0);
    }
}
@keyframes fadeInLeft {
    from {
        opacity:0;
        -webkit-transform: translatex(-100px);
        -moz-transform: translatex(-100px);
        -o-transform: translatex(-100px);
        transform: translatex(-100px);
    }
    to {
        opacity:1;
        -webkit-transform: translatex(0);
        -moz-transform: translatex(0);
        -o-transform: translatex(0);
        transform: translatex(0);
    }
}
user979331
  • 10,209
  • 56
  • 186
  • 339
  • You the add a custom class for each of you animation, make a listener on the scroll, and if the element is in the view then add the custom class that will trigger the animation... Look at the code for exemple of wow.js https://wowjs.uk/ – BENARD Patrick Jun 29 '19 at 05:21
  • 2
    You have to use JavaScript. Also, vendor prefixes aren't necessary for keyframes. – jhpratt Jun 29 '19 at 05:21
  • See [How to Check if element is visible after scrolling?](https://stackoverflow.com/questions/487073/how-to-check-if-element-is-visible-after-scrolling) and [How to tell if a DOM element is visible in the current viewport?](https://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport). Also see [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). – showdev Jun 29 '19 at 07:19
  • Please add a [mcve] to your question. – TylerH Jul 03 '19 at 20:36
  • See also https://stackoverflow.com/questions/56193172/stop-keyframe-animation-from-automatic-start-on-page-load – TylerH Jul 03 '19 at 20:37

2 Answers2

3

There is no way to have things aware of the scroll in pure CSS. You will have to use JavaScript to add a class when the element comes into the view.

One way to do that could be to use the Intersection Observer API (if you need compatibility with old browser there are polyfills available online).

let observer = new IntersectionObserver(updates => {
    updates.forEach(update => {
        if (update.isIntersecting) {
            update.target.classList.add('visible');
        } else {
            update.target.classList.remove('visible');
        }
    });
}, { threshold: 0 });

[...document.querySelectorAll('.element')].forEach(element => observer.observe(element));

Note: this method will not work (or will at least need some tweaks) if your animation makes your element go completely off to the side of the screen, as it will either never intersect with the viewport or trigger the reverse animation before ending.

JSFiddle example

Bali Balo
  • 3,138
  • 1
  • 14
  • 32
  • clean and lean solution but you should mention, it is not working for older browser nor for IE at all. source: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API – pixelquadrat Jul 09 '19 at 07:27
2

So here goes...

First of all I decoupled the animation from the selector itself and created a brand new class that only contains animation information and added the animation-fill-mode:forwards property so that the animation ends at the 100% keyframe. I added this so that the original class has opacity:0:

CSS:

.slick-slide:nth-child(odd) {
  opacity:0;

}
.slick-slide.anim:nth-child(odd) {
  -webkit-animation-name: fadeInLeft;
  -moz-animation-name: fadeInLeft;
  -o-animation-name: fadeInLeft;
  animation-name: fadeInLeft;
  -webkit-animation-duration: 1s;
  -moz-animation-duration: 1s;
  -o-animation-duration: 1s;
  animation-duration: 1s;
  -webkit-animation-delay: 1s;
  -moz-animation-delay: 1s;
  -o-animation-duration: 1s;
  animation-delay: 1s;
  -webkit-animation-fill-mode:forwards;  // added
  animation-fill-mode:forwards;          // added
}

Then you need this Javascript:

$(window).on('load scroll', function() {
    var scrollTop = $(window).scrollTop(),
        windowHeight = $(window).height(),
        threshold = 200;

  $('.slick-slide:nth-child(odd)').each(function() {
        var offTop=$(this).offset().top;
    if ((scrollTop+windowHeight) > offTop) { // you can add -threshold here as scrollTop+windowHeight-threshold in pixels
    $(this).addClass('anim');
    }
  });
});

What the Javascript does is: as soon as one of the selector classes is on-screen - by calculating window scrollTop minus window height, then the anim class is applied on the selector. I also added an optional threshold variable you can use to alter the point where the animation triggers - eg 200px on the screen.

I added some styling to the slick-slide elements in the example so that some of them are off screen initially.

Here is a working fiddle. https://jsfiddle.net/tun51xq6/1/

scooterlord
  • 14,208
  • 11
  • 43
  • 65