Search code examples
javascriptcsscss-animationsonscroll

JavaScript Fade in on scroll once faded in don't fade out


Just a quick question, complete novice when it comes to JavaScript but am learning! I have this code where when the elements have values of data-animate-in="fadeIn" data-animate-in-delay="100" They fade in on scroll. That all works fine, the only problem I'm having is that they are now fading out when I scroll down the page... Is there a way I can have it so once it fades in the first time, it stays solid.

Here's my code

JavaScript

    $(function() {

  var html = $('html');

  // On Screen

  $.fn.isOnScreen = function() {
    var elementTop = $(this).offset().top,
      elementBottom = elementTop + $(this).outerHeight(),
      viewportTop = $(window).scrollTop(),
      viewportBottom = viewportTop + $(window).height();
    return elementBottom > viewportTop && elementTop < viewportBottom;
  };

  function detection() {
    for (var i = 0; i < items.length; i++) {
      var el = $(items[i]);

      if (el.isOnScreen()) {
        el.addClass("in-view");
      } else {
        el.removeClass("in-view");
      }
    }
  }

  var items = document.querySelectorAll(
    "*[data-animate-in], *[data-detect-viewport]"
  ),
    waiting = false,
    w = $(window);

  w.on("resize scroll", function() {
    if (waiting) {
      return;
    }
    waiting = true;
    detection();

    setTimeout(function() {
      waiting = false;
    }, 100);
  });

  $(document).ready(function() {
    setTimeout(function() {
      detection();
    }, 500);

    for (var i = 0; i < items.length; i++) {
      var d = 0,
        el = $(items[i]);
      if (items[i].getAttribute("data-animate-in-delay")) {
        d = items[i].getAttribute("data-animate-in-delay") / 1000 + "s";
      } else {
        d = 0;
      }
      el.css("transition-delay", d);
    }
  });
});

CSS

    /* -- Animation -- */

[data-animate-in] {
    opacity: 0;
    transition: transform 0.8s ease, opacity 0.8s ease
}

[data-animate-in="up"] {
    transform: translate3d(0, 24px, 0)
}

[data-animate-in="left"] {
    transform: translate3d(-25%, 0, 0)
}

[data-animate-in="right"] {
    transform: translate3d(25%, 0, 0)
}

[data-animate-in="down"] {
    transform: translate3d(0, -24px, 0)
}

[data-animate-in="fadeIn"] {
    transform: translate3d(0, 0, 0)
}

[data-animate-in].in-view {
    opacity: 1;
    transform: translate3d(0, 0, 0);
    -webkit-transform: translate3d(0, 0, 0);
    transition: transform 0.6s ease, opacity 0.6s ease
}

.fade-in {
    opacity: 0;
    transition: opacity 1s ease
}

.page-loaded .fade-in,.page-loaded.fade-in {
    opacity: 1
}

Any recommendations or improvement on my code, please let me know. Will be helpful as only just starting out!

Thanks :)


Solution

  • As stated in my comment I would recommend to remove the data-animate-in attribute after the element has entered the viewport and the animation completes. Removing the attribute needs to be performed with a delay as the CSS rules also reference the attribute and removing it directly will make the element lose the CSS rules. This can be done via window.setTimeout():

    if (el.isOnScreen()) {
        el.addClass("in-view");
        setTimeout(function() {
          this.removeAttr('data-animate-in');
        }.bind(el), 800);
      } else {
        el.removeClass("in-view");
      }
    

    I used 800 ms as delay as the CSS animation is also set to 0.8s:

    transition: transform 0.8s ease, opacity 0.8s ease
    

    If you want to change the duration please also change the delay to match the transition.

    An updated Fiddle can be found here.