简体   繁体   中英

Why the callback of Intersection Observer API is executed when even viewport didn't reach the threshold?

const imgTargets = document.querySelectorAll('img[data-src]');
 
const loadImg = function (entries, observer) {
  const [entry] = entries;
 
  if (!entry.isIntersecting) return;
 
  // Replace src with data-src
  entry.target.src = entry.target.dataset.src;
 
  entry.target.addEventListener('load', function () {
    entry.target.classList.remove('lazy-img');
  });
 
  observer.unobserve(entry.target);
};
 
const imgObserver = new IntersectionObserver(loadImg, {
  root: null,
  threshold: 0.5,
  // rootMargin: '200px', (comment)
});
 
imgTargets.forEach(img => imgObserver.observe(img));

The codes down below is applying the lazy images effect for images on scroll, so i used the Intersection Observer API.

As you can see, i set the threshold is 50%, that's mean, the viewport should intersect 50% of the image height to make the callback executed.

But, when i scrolled just to reached the very top point of the image, the callback is executed ¯_(ツ)_/¯. You can see at the picture.

You can see the demo of this effect at here , which is the effect that im trying to build on my own, and my HTML and the CSS codes are just the same with this demo website.

The proof of my situations

Pls help me to find out, although the effect is also satisfying but i want to know why this is happening, thank you so much, readers.

And here is my html and css codes that are related to the images and the parent sections: HTML

  <section class="section" id="section--1">
    <div class="section__title">
      <h2 class="section__description">Features</h2>
      <h3 class="section__header">
        Everything you need in a modern bank and more.
      </h3>
    </div>


    <!-- The container of the images and the descriptions -->
    <div class="features">
      <!-- First image --> <img src="img/digital-lazy.jpg" data-src="img/digital.jpg" alt="Computer" class="features__img lazy-img" />
      <div class="features__feature">
        <div class="features__icon">
          <svg>
            <use xlink:href="img/icons.svg#icon-monitor"></use>
          </svg>
        </div>
        <h5 class="features__header">100% digital bank</h5>
        <!-- Descriptions of first image --> <p>
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Unde alias
          sint quos? Accusantium a fugiat porro reiciendis saepe quibusdam
          debitis ducimus.
        </p>
      </div>

      <div class="features__feature">
        <div class="features__icon">
          <svg>
            <use xlink:href="img/icons.svg#icon-trending-up"></use>
          </svg>
        </div>
        <h5 class="features__header">Watch your money grow</h5>
        <!-- The second description of the second image --> <p>
          Nesciunt quos autem dolorum voluptates cum dolores dicta fuga
          inventore ab? Nulla incidunt eius numquam sequi iste pariatur
          quibusdam!
        </p>
      </div>
      <!-- Second image --> <img src="img/grow-lazy.jpg" data-src="img/grow.jpg" alt="Plant" class="features__img lazy-img" />

      <!-- Third image --> <img src="img/card-lazy.jpg" data-src="img/card.jpg" alt="Credit card" class="features__img lazy-img" />
      <div class="features__feature">
        <div class="features__icon">
          <svg>
            <use xlink:href="img/icons.svg#icon-credit-card"></use>
          </svg>
        </div>
        <h5 class="features__header">Free debit card included</h5>
        <!-- The third description of the third image --> <p></p><p>
          Quasi, fugit in cumque cupiditate reprehenderit debitis animi enim
          eveniet consequatur odit quam quos possimus assumenda dicta fuga
          inventore ab.
        </p>
      </div>
    </div>


  </section>

And here is the css:

/* Should notice*/

.features {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4rem;
  margin: 0 12rem;
}

.features__img {
  width: 100%;
}

.lazy-img {
  filter: blur(20px);
}

.features__feature {
  align-self: center;
  justify-self: center;
  width: 70%;
  font-size: 1.5rem;
}

/* The styles i think its not important but related to the feature section*/
.features__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--color-primary-opacity);
  height: 5.5rem;
  width: 5.5rem;
  border-radius: 50%;
  margin-bottom: 2rem;
}

.features__icon svg {
  height: 2.5rem;
  width: 2.5rem;
  fill: var(--color-primary);
}

.features__header {
  font-size: 2rem;
  margin-bottom: 1rem;
}

Please, if you need some more informations, please call me to give, i will always ready to provide, thank you so much.

The images are here The images have the name which is contains -lazy are the images that are have the low numebrs of pixels, that i use the first before, and then add the class of the blur filters, and the, when the users scroll to the images, they will change to the orginal ones and remove the blur filers.

Before an img is loaded the system does not have any height for it. Therefore the img element which you are observing triggers the observed 'isIntersecting' immediately it comes into the bottom of the viewport because 50% of nothing is nothing.

I don't know exactly what you want to do but here is a snippet where an invented height is added to a div wrapping an img element and when 50% of this is showing in the viewport, the img gets loaded.

Possibly you could find out the heights of each image before they are loaded and use this technique to put in the proper heights, but it looks a bit odd an image suddenly appearing when there has been a blank space at the bottom of the page.

 const imgTargets = document.querySelectorAll('div.imgwrapper'); const loadImg = function (entries, observer) { const [entry] = entries; if (.entry;isIntersecting) return. // Replace src with data-src entry.target.firstElementChild.src = entry.target.firstElementChild.dataset;src. entry.target,addEventListener('load'. function () { entry.target.classList;remove('lazy-img'); }). observer.unobserve(entry;target); }, const imgObserver = new IntersectionObserver(loadImg: { root, null: threshold. 0,5: // rootMargin, '200px'; (comment) }). imgTargets.forEach(img => imgObserver;observe(img));
 .talldiv { background: linear-gradient(cyan,lime); height: 150vh; }.imgwrapper { height: 200vh; background-color: pink; }
 <div class="talldiv">SCROLL DOWN</div> <div class="imgwrapper"><img src="" data-src="https://picsum.photos/id/1015/200/300.jpg" /> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM