Home > database >  Trouble with fading image into viewport through CSS/JS
Trouble with fading image into viewport through CSS/JS

Time:12-04

I am attempting to make an image on a website fade in and up when a user scrolls the image into the viewport. The code I have so far is below. However, when I run this code I get a 404 error output. Any assistance is appreciated! I am quite new to JS and have been trying to figure this out for a while.

Here is my CSS.

.section3 {
        opacity: 0;
        transform: translateY(20vh);
        visibility: hidden;
        transition: opacity 0.6s ease-out, transform 1.2s ease-out;
        will-change: opacity, visibility;
    }
.fade {
        opacity: 1;
        transform: none;
        visibility: visible;
    }

Below is the HTML and JS.

<section id="section3" >
        <img style="width: 100%;" src="lovethyneighbor.jpg">
</section>

<script>
        var section3 = document.getElementById("section3");
        var location = section3.getBoundingClientRect();

        if (location.top >= 0) {
            document.getElementById("section3").classList.add("fade");
        } else {
            document.getElementById("section3").classList.add("section3");
        }
</script>

CodePudding user response:

Introducing the Intersection Observer API! This is included in JavaScript and is a great tool for triggering an event when an element is in the viewport.

It's a really powerful tool and I'd highly suggest using this over getBoundingClientRect(). One of the main reasons for this is with your code:

if (location.top >= 0) {
     document.getElementById("section3").classList.add("fade");
} 

else {        
     document.getElementById("section3").classList.add("section3");
}

You will have to run a function on every single mousewheel event, which is unreliable and can hurt performance. If you're using Intersection Observer, the API will "watch" your page and will run a function whenever the element is in the viewport. The code below is explained through inline comments.

Scalable with multiple elements that need different animations

// the sections/containers
const sections = document.querySelectorAll("section.section");

// options for the intersection function
const options = {
  root: null,
  threshold: 0.5, // how much of the element should be visible before the function is triggered? from 0 - 1
  rootMargin: "0px 0px 0px 0px" // default rootmargin value
};

// the observer - with foreach we can trigger multiple elements with multiple animations if need be
let observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {

    // the element that is going to be animated
    const block = entry.target.querySelector("img.fader");

    // elements to be animated, e.g.
    // if multiple elements with animations need to run inside the same section
    const animationBlocks = entry.target.querySelectorAll("[data-animation]");

    // when the element is triggered
    if (entry.isIntersecting) {
      // foreach, if multiple animations need to run on the same element
      animationBlocks.forEach((animation) => {
        animationClass = animation.dataset.animation;

        // adding the data-animation class class to the element, so the animation can run
        animation.classList.add(animationClass);
      });
    }
  });
}, options);

observer.observe(document.querySelector("section.section"));

// running the animations
document.addEventListener("DOMContentLoaded", function() {
  Array.from(sections).forEach(function(element) {
    observer.observe(element);
  });
});
body {
  height: 300vh;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  background-color: teal;
  gap: 400px;
}

/* starting values */
[data-animation="fadeInUp"] {
  opacity: 0;
  transform: translate3d(0, 20px, 0);
}

/* when classname is applied to the element, run the animation */
.fadeInUp {
  animation-name: fadeInUp;
  animation-duration: 0.6s;
  animation-fill-mode: both;
}

/* the animation */
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translate3d(0, 20px, 0);
  }
  to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}
<section id="section2" >
  <img data-animation="fadeInUp"  style="width: 100%;" src="https://picsum.photos/200/300">
</section>

<section id="section3" >
  <img data-animation="fadeInUp"  style="width: 100%;" src="https://picsum.photos/200/300">
</section>

Simple function with single element and single animation

const sections = document.querySelectorAll("section.section");

const options = {
  root: null,
  threshold: 0.5
};

let observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {

    const block = entry.target.querySelector("img.fader");

    if (entry.isIntersecting) {
      block.classList.add('fadeInUp');
    }
  });
}, options);

observer.observe(document.querySelector("section.section"));

// running the animations
document.addEventListener("DOMContentLoaded", function() {
  Array.from(sections).forEach(function(element) {
    observer.observe(element);
  });
});
body {
  height: 300vh;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  background-color: teal;
  gap: 400px;
}

img.fader {
  opacity: 0;
  transform: translate3d(0, 20px, 0);
}

.fadeInUp {
  animation-name: fadeInUp;
  animation-duration: 0.6s;
  animation-fill-mode: both;
}


/* the animation */

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translate3d(0, 20px, 0);
  }
  to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}
<section id="section2" >
  <img data-animation="fadeInUp"  style="width: 100%;" src="https://picsum.photos/200/300">
</section>

<section id="section3" >
  <img  style="width: 100%;" src="https://picsum.photos/200/300">
</section>

  • Related