Плавное появление при скролле

Элементы анимированно появляются при входе в viewport — IntersectionObserver добавляет CSS-класс, transition делает анимацию.

Задача

Секции лендинга, карточки, блоки текста должны появляться с плавной анимацией при прокрутке к ним — эффект «reveal on scroll» без тяжёлых библиотек.

Решение

<!-- Добавь класс .reveal к элементам, которые должны появляться -->
<section class="reveal">Секция 1</section>
<div class="reveal">Карточка</div>
<article class="reveal">Статья</article>
/* Начальное состояние: скрытый и сдвинутый вниз */
.reveal {
  opacity: 0;
  transform: translateY(40px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

/* Видимое состояние */
.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

/* Задержки для каскадного появления (опционально) */
.reveal:nth-child(2) { transition-delay: 0.1s; }
.reveal:nth-child(3) { transition-delay: 0.2s; }
.reveal:nth-child(4) { transition-delay: 0.3s; }

/* Уважаем настройки пользователя */
@media (prefers-reduced-motion: reduce) {
  .reveal { transition: none; opacity: 1; transform: none; }
}
const elements = document.querySelectorAll('.reveal');

const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        entry.target.classList.add('visible');
        observer.unobserve(entry.target); // показать только один раз
      }
    });
  },
  {
    threshold: 0.15,      // 15% элемента должно быть видно
    rootMargin: '0px 0px -50px 0px', // чуть позже — не сразу у края
  }
);

elements.forEach((el) => observer.observe(el));

Варианты анимации через data-атрибут:

<div class="reveal" data-reveal="fade-left">Слева</div>
<div class="reveal" data-reveal="fade-right">Справа</div>
<div class="reveal" data-reveal="zoom">Zoom</div>
[data-reveal="fade-left"]  { transform: translateX(-40px); }
[data-reveal="fade-right"] { transform: translateX(40px); }
[data-reveal="zoom"]       { transform: scale(0.85); }
[data-reveal].visible      { transform: none; opacity: 1; }

Ключевые моменты

  • IntersectionObserver + CSS class — минимум JS, анимация полностью в CSS.
  • observer.unobserve() — элемент появляется один раз и перестаёт отслеживаться.
  • @media (prefers-reduced-motion: reduce) — обязательна; пользователи с вестибулярными нарушениями отключают анимации.
  • rootMargin: '0px 0px -50px 0px' — нижний отступ 50px, элемент появится чуть позже прихода в viewport.

Варианты

  • AOS (animate on scroll) — готовая библиотека с десятками анимаций, data-aos атрибуты.
  • GSAP ScrollTrigger — для сложных timeline-анимаций, привязанных к позиции скролла.

Связанные рецепты / темы