Как можно последовательно анимировать одновременно отображаемые в браузере блоки в зависимости от различных условий их видимости?

Добрый день. У меня возникла проблема с анимацией при прокрутке страницы, которую я реализую с помощью AOS.js. Иногда несколько блоков (например, три) одновременно попадают в область видимости браузера. Мне необходимо, чтобы их анимация появления происходила последовательно, с задержкой между каждым блоком. Однако, если эти три блока не одновременно отображаются в области видимости (например, на мобильных устройствах они располагаются друг под другом), задержка для последующих блоков (второго и третьего) должна отсутствовать. В случае, если два блока видны, а третий - нет, задержка у второго блока относительно первого сохраняется, а у третьего - нет. Количество блоков может варьироваться. Как правильно реализовать эту функциональность? 

Дополнительно, посмотрите пример работы на сайте bannermaker.by в разделе портфолио, где контент генерируется динамически, а у меня статические заранее подготовленные блоки. 

Также прикладываю картинку для большей наглядности (цифры обозначают задержку появления блоков при входе в область видимости):
  • 5 сентября 2024 г. 9:33
Ответы на вопрос 2
Для реализации анимации блоков, как вы описали, вам потребуется создать кастомное поведение, используя JavaScript, чтобы обрабатывать видимость блоков и применять задержки при анимации. Вот один из возможных подходов, используя Intersection Observer API и CSS-анимации.

### 1. Структура HTML

У вас должны быть блоки, которые вы хотите анимировать:

```html
<div class="animated-block">Block 1</div>
<div class="animated-block">Block 2</div>
<div class="animated-block">Block 3</div>
<!-- и так далее -->
```

### 2. Стили CSS

Определите стиль для анимации. Например:

```css
.animated-block {
    opacity: 0;
    transform: translateY(20px); /* Начальная позиция */
    transition: opacity 0.5s ease, transform 0.5s ease;
}

.animated-block.animate {
    opacity: 1;
    transform: translateY(0); /* Конечная позиция */
}
```

### 3. JavaScript для управления анимацией

Теперь используйте Intersection Observer для отслеживания видимости блоков:

```javascript
const blocks = document.querySelectorAll('.animated-block');
let delay = 0;

const options = {
    root: null,
    rootMargin: '0px',
    threshold: 0.1 // 10% видимости
};

const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            // Удаляем старую задержку и применяем новую
            entry.target.style.transitionDelay = `${delay}s`;
            entry.target.classList.add('animate');

            // Увеличиваем задержку для следующего блока, если он виден
            delay += 0.3; // Пример: задержка в 300 мс
        } else {
            // Если блок выходит из видимости, сбрасываем задержку
            delay = 0;
        }
    });
}, options);

// Наблюдаем за каждым блоком
blocks.forEach(block => {
    observer.observe(block);
});
```

### 4. Альтернативная обработка для мобильных устройств

Если вы хотите, чтобы анимация была мгновенной на мобильных устройствах, можно добавить проверку ширины экрана:

```javascript
if (window.innerWidth <= 768) { // Или другое значение в пикселях для мобильных устройств
    delay = 0; // Отключаем задержку
}
```

### 5. Итоговая логика

Теперь, если блоки будут одновременно видимы, они будут появляться с заданной задержкой. Если один из блоков станет невидимым, задержка для других блоков сбрасывается, что позволяет;

- Последовательно анимировать их появление.
- Избегать задержки анимации для блоков, которые не видны.

Вы также можете настроить параметры `threshold` и `rootMargin` в зависимости от ваших потребностей для более точного отслеживания видимости блоков.

Этот подход даст вам гибкость и контроль над анимацией блоков в зависимости от их видимости в области просмотра.
Всем привет. Решил свою проблему через дополнительное использование IntersectionObserver, который отслеживает блоки, помеченные AOS атрибутами. Инициализировал сам AOS через таймаут в 50 (не знаю зачем это нужно, но без этого не работает). Observer отслеживает теги, у которых еще не задан delay, как только delay через скрипт задается, блок перестает отслеживаться. Накидывание delay выполнено через FIFO. Вот рабочий код, может кому пригодиться: 
const stack = []
const delayFactor = 300

const options = {
  rootMargin: '0px',
  threshold: 0.2,
}

const callback = entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      stack.push(entry.target)

      const delay = (stack.length - 1) * delayFactor

      entry.target.setAttribute('data-aos-delay', `${delay}`)

      setTimeout(() => {
        stack.shift()
      }, delay)
    }
  })
}

const observer = new IntersectionObserver(callback, options)

const elementsToTrack = document.querySelectorAll(
  '[data-aos]:not([data-aos-delay])'
)

elementsToTrack.forEach(element => {
  observer.observe(element)
})


Пример работы можно посмотреть на сайте: https://yourbanner.ru
Похожие вопросы