1

Given an animating (transforming) row of images, detect when each one reaches the center so we can make some changes (e.g., adding styling like filter: grayscale)

row of images with one that is not black and white (as it reached middle of screen)

I've enlisted IntersectionObserver and gotten close. In fact my solution works great in Firefox but only works in Chrome if the mouse is moving and doesn't work at all in Safari. Even if I tweak the options parameter behavior seems sporadic unless in Firefox.

Codepen

const options = {
  root: document.body,
  rootMargin: '0% -50% 0% -50%',
  threshold: 0,
}

const observer = new IntersectionObserver((entries) => { 
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      entry.target.style.filter = 'grayscale(0%)'
    } else {
      entry.target.style.filter = 'grayscale(100%)'
    }
  })
}, options)

const items = document.querySelectorAll('.img-container img');
items.forEach(img => observer.observe(img))
0

1 Answer 1

1

Use requestAnimationFrame() and find the element in the center using elementFromPoint():

const wrapper = document.querySelector('.wrapper');
const images = document.querySelectorAll('.wrapper img');

const updateActiveImage = () => {
  const { left, top, width, height } = wrapper.getBoundingClientRect();
  const centerX = left + width / 2;
  const centerY = top + height / 2;

  const imgAtCenter = document.elementFromPoint(centerX, centerY);
  images.forEach(img => img.classList.remove('active'));

  if (imgAtCenter) {
    imgAtCenter.classList.add('active');
  }
  requestAnimationFrame(updateActiveImage);
};

requestAnimationFrame(updateActiveImage);
body {
  background: black;
  margin: 0;
}

.wrapper {
  overflow: hidden;
}

img {
  width: 300px;
  height: 300px;
  object-fit: cover;
  transition: filter 200ms ease-in-out;
  &:not(.active) {
    filter: grayscale(100%);
  }
}

.img-container {
  display: flex;
  gap: 24px;
  animation: marquee 40s linear infinite;
}

@keyframes marquee {
  0% {
    transform: translateX(0);
  }
  to {
    transform: translateX(calc(-100% - 24px));
  }
}
<div class="wrapper">
  <div class="img-container">
    <img src="https://www.wonderwall.com/wp-content/uploads/sites/2/2020/11/shutterstock_editorial_10552447px.jpg?x=514&y=800&icq=74&sig=639b09155acfa34ee0f71886a1556c55" />
    <img src="https://hips.hearstapps.com/hmg-prod/images/gettyimages-1280266077.jpg" />
    <img src="https://cdn-0.atwoodmagazine.com/wp-content/uploads/2018/01/Chappell-Roan-2018.jpg" />
    <img src="https://e00-marca.uecdn.es/assets/multimedia/imagenes/2022/06/27/16563602316989.jpg" />
    <img src="https://www.expressandstar.com/resizer/SxBF0kXCbz34fI7twkxcDR8Rdi4=/1200x0/cloudfront-us-east-1.images.arcpublishing.com/mna/MWUDEBVNBZBYFAQSYYVPEYATGQ.jpg" />
    <img src="https://parade.com/.image/t_share/MTk3OTcwMTgwMDE2NDQ5MzA5/lindsay-lohan-nyc-2022.jpg" />
    <img src="https://i.pinimg.com/originals/5c/b3/02/5cb302c78b1bb14e57194bdc31e7c502.jpg" />
    <img src="https://s.yimg.com/uu/api/res/1.2/TVnjyBmzZWNlxeO5CvVkfQ--~B/aD0xMjAwO3c9MTIwMDthcHBpZD15dGFjaHlvbg--/https://media.zenfs.com/en/e__181/b609e20726211710ba3bef9a8dba183d" />
    <img src="https://wallpapercave.com/wp/wp4434081.jpg" />
    <img src="https://celebsuburb.com/wp-content/uploads/2024/09/obi-ndefo-death-1.jpg" />
  </div>
</div>

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.