Присвоить класс блоку, оказавшемуся в центральной части браузера при горизонтальной прокрутке

Для упрощения, опишу задачу так. Есть блок, внутри которого прокручиваются горизонтально другие блоки. В каждом из этих блоков абсолютно позиционирован еще один блок в виде цветного квадрата. Необходимо каждому из этих квадратов присваивать класс .visible в момент, когда этот квадрат докручивается до центра экрана. Центром можно считать область, отстоящую от краёв экрана на 30% слева и справа, вне зависимости от его исходной ширины. Буду благодарен за подсказку, поскольку в js не силён.

.container{
  max-width: 100%;
  overflow-x: auto;
  white-space: nowrap;
}

.block{
  position:relative;
  width: 800px;
  height: 200px;
  display: inline-block;
  background-color: rgba(0,0,0,0.2);
}
.square1 {
  width:30px;
  height:30px;
  background:red;
  position:absolute;
  right:100px;
  bottom:80px;
}
.square2 {
  width:30px;
  height:30px;
  background:blue;
  position:absolute;
  right:200px;
  bottom:120px;
}
.square3 {
  width:30px;
  height:30px;
  background:green;
  position:absolute;
  right:300px;
  bottom:50px;
}
.square4 {
  width:30px;
  height:30px;
  background:orange;
  position:absolute;
  right:400px;
  bottom:70px;
}
<div class="container">
  <div class="block">
    <div class="square1"></div>
  </div>
  <div class="block">
    <div class="square2"></div>    
  </div>
  <div class="block">
    <div class="square3"></div>  
  </div>
  <div class="block">
    <div class="square4"></div>    
  </div>
</div>


Ответы (1 шт):

Автор решения: Alexey Vladimirov

Базовый пример, в котором текущему блоку, занимающему большую часть контейнера, добавляется класс active. А дальше уже можете настроить поведение содержимого.

Если цель не в том, чтобы активировать содержимое блока в поле зрения, а нужна более замысловатая механика, значит, я неправильно понял, извините. (Тогда может быть проще слушать событие scroll у контейнера и, выполнять манипуляции с элементами в зависимости от текущего значения scrollLeft)

const slides = document.querySelectorAll('.block');
slides.forEach((i) => {
  if (i) {
    const observer = new IntersectionObserver((entries) => {
      observerCallback(entries, observer, i)
    }, {
      threshold: 0.5
    });
    observer.observe(i);
  }
})

const observerCallback = (entries, observer, header) => {
  entries.forEach((entry, i) => {
    if (entry.isIntersecting) {
      Array.from(document.querySelectorAll('.block')).forEach((el) => el.classList.remove('active'));
      entry.target.classList.add('active');
    }
  });
};
.container {
  max-width: 100%;
  overflow-x: auto;
  white-space: nowrap;
}

.block {
  position: relative;
  width: 800px;
  height: 180px;
  max-width: 80%;
  display: inline-block;
  background-color: rgba(0, 0, 0, 0.2);
  border: solid 2px transparent;
}

.block.active {
  border: solid 2px red;
}

.square1 {
  width: 30px;
  height: 30px;
  background: red;
  position: absolute;
  right: 100px;
  bottom: 80px;
}

.square2 {
  width: 30px;
  height: 30px;
  background: blue;
  position: absolute;
  right: 200px;
  bottom: 120px;
}

.square3 {
  width: 30px;
  height: 30px;
  background: green;
  position: absolute;
  right: 300px;
  bottom: 50px;
}

.square4 {
  width: 30px;
  height: 30px;
  background: orange;
  position: absolute;
  right: 400px;
  bottom: 70px;
}
<div class="container">
  <div class="block">
    <div class="square1"></div>
  </div>
  <div class="block">
    <div class="square2"></div>
  </div>
  <div class="block">
    <div class="square3"></div>
  </div>
  <div class="block">
    <div class="square4"></div>
  </div>
</div>

→ Ссылка