0

I followed some suggestions on other questions on how to add classes to element when it becomes visible on the screen if you scroll. I keep getting the same results: when I start scrolling the class gets added even though my element is not visible.

function isScrolledIntoView(elem) {
    var $window = $(window),
        docViewTop = $window.scrollTop(),
        docViewBottom = docViewTop + $window.height(),
        elemTop = $(elem).offset().top ,
        elemBottom = elemTop + $(elem).outerHeight();

    return ((elemBottom  <= docViewBottom) && (elemTop >= docViewTop));
}

$(window).on("scroll", function() {

    $('#card1').each(function() {
        if (isScrolledIntoView(this)) {
            $(this).addClass('cardScroll');
            console.log('Class added');
        } else {
            $(this).removeClass('cardScroll');
        }
    });

});

"Class added" keeps logging when I start scrolling from the top of the page and my element (#card1) is only in the middle of the page.

HTML:

<div class="col-lg-4 d-flex justify-content-around">
    <div  class="card" id="card1" style="width: 18rem;">
        <div class="rounded-div">
            <img class="card-img-top" src="" alt="">
         </div>
         <div style="text-align: center;" class="card-body">
             <h5 class="card-title">Dummy Text</h5>
             <p class="card-text">Dummy text</p>  
          </div>
     </div>
  </div>

CSS:

.cardScroll {
        background-color: #d1e4f3;
        box-shadow: 10px 10px 16px 0 rgb(31, 31, 31);
        -webkit-transition: box-shadow 0.3s ease-out;
        -moz-transition:  box-shadow 0.3s ease-out;
        -o-transition:  box-shadow 0.3s ease-out;
        transition: box-shadow 0.3s ease-out;
    }
Coder_98
  • 117
  • 3
  • 10

2 Answers2

1

I changed my isScrolledIntoView function to the following and it seemed to fix it:

function isScrolledIntoView(el) {
var rect = el.getBoundingClientRect();
var elemTop = rect.top;
var elemBottom = rect.bottom;

// Only completely visible elements return true:
var isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
// Partially visible elements return true:
//isVisible = elemTop < window.innerHeight && elemBottom >= 0;
    return isVisible;
}

I found the answer here How to Check if element is visible after scrolling?

Coder_98
  • 117
  • 3
  • 10
-1

You should not use .on('scroll') for this since this can cause performance issues.

For problems like yours you can easily use the Intersection Observer (IO) With IO you can detect when an element comes into view (or leaves it) and react to it.

First, you have to set the options for the IO and create it:

var options = {
  rootMargin: '0px',
  threshold: 1.0
}

var observer = new IntersectionObserver(callback, options);

if we leave out 'root' from options, we watch the whole window. And with 'threshold' we define that we want our 'callback' function to be executed once it is at least 100% visible.

Then we define which elements we want to observe, in your case it would be 'cards'

var target = document.querySelector('.card');
observer.observe(target);

Finally, we have to define the callback function we said we want to execute once a 'card' element is fully visible:

var callback = function(entries, observer) { 
  entries.forEach(entry => {
    // Each entry describes an intersection change for one observed
  });
};

Edit: If you need to support older browsers than use this (official) polyfill from w3c, it recreates intersection observer with listening to scroll events. So it will still be slower on older browsers, nothing you can do about it here. But on newer ones there will be an increase in performance.

cloned
  • 6,346
  • 4
  • 26
  • 38
  • that `Intersection Observer API` isn't yet standardized and some browser doesn't support it at all (no doubt `IE` is one of them). Anyway, I think that's not an option due to the browser support and because it still a `draft`. – ThS Jul 29 '19 at 15:22
  • It is **not** a draft, it is supported by [every major browser.](https://caniuse.com/#feat=intersectionobserver) I also linked a polyfill for browsers that don't support it (like IE). So it's definitely usable and recommendable. – cloned Jul 30 '19 at 06:43
  • it's a **[working draft](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Specifications)**. – ThS Jul 30 '19 at 09:20
  • You are right, it's a draft (it was too early, sorry) but it's still fully functional in every browser (except ie). It can be made available through the polyfill. It just has much better performance than listening to scroll events. – cloned Jul 30 '19 at 09:21
  • Logically, we take the trouble to try creating a polyfill when a functionality is *standard* and *supported* by all the modern browsers. Here, we have the support which is good, but the `API` still not declared as **standard**. – ThS Jul 30 '19 at 09:24
  • This is getting off topic, but I doubt that that there will be major changes to IO in forseeable future, more so if it's just about checking how much an element intersects with the screen. Otherwise it wouldn't have been implemented yet. So yes, it's not fully standardised yet but this shouldn't discourage you from using it. "some browser doesn't support it at all" is just not a true statement about IO. – cloned Jul 30 '19 at 09:31
  • I did **NOT** discourage anyone from using it, just said that is works but it isn't standard yet. – ThS Jul 30 '19 at 09:33