IntersectionObserver - How to tell IF one of the elements are still in the viewport?

Viewed 368

I' trying to make a menu that change color when the background has a specific class. I'm using Intersection Observers, but it doesn't work. Basically i want something like this: If(ONE of the elements are in view) { add a class to the menu } If(ALL of the elements out of view) { remove a class to the menu }

Check out this codepen: https://codepen.io/andreas-rasmussen/pen/oNZKJwm

Basically it's suppose to work like this header: https://www.eiffelcph.dk

const options = {
  root: null,
  rootMargin: "0px 0px 87% 0px", 
  threshold: 0
};

let callback = (entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      $(".logo").addClass("white");
    } else {
      $(".logo").removeClass("white");
    }
  });

};
let observer = new IntersectionObserver(callback, options);
document.querySelectorAll(".dark-menu").forEach((darkmenu) => {
  observer.observe(darkmenu);
});

1 Answers

We need to remember how many items are in view. You could do this through setting a count but an alternative is to remember which items are in view.

This snippet remembers whether an item is in view by setting/removing the attribute data-isin. If any of the items has data-isin set it sets the logo class to white.

let callback = (entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.setAttribute('data-isin', '1');
    } else(entry.target.removeAttribute('data-isin'));
  });
  logo.classList.remove('white');
  for (i = 0; i < divs.length; i++) {
    if (divs[i].getAttribute('data-isin')) {
      logo.classList.add('white');
      break;
    }
  }
};

const observer = new IntersectionObserver(callback);
const divs = document.querySelectorAll('.items div');
const logo = document.querySelector('.logo');

divs.forEach(div => {
  observer.observe(div);
});
body {
  background: pink;
}

.white {
  background: white;
}

.logo {
  width: 10vmin;
  height: 10vmin;
  border-style: solid;
  position: fixed;
  z-index: 1;
}

.items div {
  border-style: solid;
  height: 30vh;
}
<div class="logo"></div>
<div class="items">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>
<div style="height: 200vh; background: cyan; position: relative;">FILLER</div>

Related